52일차 TypeScript

정상희·2025년 6월 17일

코딩공부

목록 보기
60/60

현재 오즈코딩스쿨 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.

1. TypeScript

1) TypeScript란?

TypeScript 는 JavaScript 의 상위 집합(super set)으로, 자바스크립트의 모든 기능을 포함하면서 추가적인 기능을 제공합니다.

  • 정적 타입 검사

    • JavaScript는 동적 타입 언어로, 변수의 타입이 런타임에 결정됩니다. 반면 TypeScript는 정적 타입 언어로 컴파일 시점에 변수의 타입을 검사합니다.
    • TypeScript를 사용하면 타입 오류를 사전에 발견하여 코드의 안정성을 높일 수 있습니다.
  • 컴파일러(Compiler)

    • TypeScript 는 JavaScript 와 달리 브라우저에서 실행 하려면 JavaScript 파일로 변환하는 과정을 거쳐야 합니다. 이러한 변환 과정을 (컴파일)compile 이라 합니다. 이 변환 작업은 TypeScript 컴파일러(tsc)에 의해 수행됩니다.
  • 슈퍼셋(Superset)

    • TypeScript는 JavaScript의 모든 기능을 포함하고 있으며, 여기에 타입 시스템과 추가적인 언어 기능을 제공합니다. 따라서 기존 JavaScript 코드를 그대로 사용할 수 있습니다.

2) TypeScript 개요

TypeScript는 Microsoft에서 개발한 오픈 소스 프로그래밍 언어입니다. 대규모 프로젝트에서 코드의 유지보수성과 가독성을 높이는 것을 목표로 합니다. TypeScript 는 개발자들에게 강력한 도구를 제공하여 코드 작성 시 타입을 명시하고, 컴파일 단계에서 타입 오류를 확인할 수 있게 합니다. 이를 통해 런타임 오류를 줄이고, 더 안전하고 신뢰성 있는 코드를 작성할 수 있습니다.


3) TypeScript 주요 특징

  • 크로스 플랫폼 : TypeScript는 JavaScript 가 실행되는 모든 플랫폼에서 실행됩니다.
  • 객체 지향 언어 : TypeScript는 클래스, 인터페이스, 모듈과 같은 강력한 객체 지향 프로그래밍 기능을 제공합니다.
  • 정적 타입 검사 : TypeScript는 정적 타이핑을 사용하며, 이는 타입 annotation(타입 주석)을 통해 수행됩니다. 이를 통해 컴파일 시에 타입 검사가 가능하므로, 스크립트를 매번 실행하지 않고도 코드 작성 중에 오류를 찾기 쉽습니다.
  • 타입 추론 : 변수가 타입 없이 선언되면, 그 값에 기반하여 타입을 추론하는 기능을 제공합니다.
  • 선택적 정적 타이핑 : TypeScript의 정적 타입은 선택적입니다.
  • DOM 조작 : JavaScript 처럼 TypeScript도 DOM을 조작하는 데 사용할 수 있습니다.
  • ES6 기능 포함 : TypeScript는 클래스, 인터페이스, 화살표 함수 등 대부분의 기능을 포함하고 있습니다.


    출처 : github 2023 octoverse

TypeScript는 2023년 Github 기준 가장 많이 사용되고(3위) 사용량이 가장 많은 언어(3위) 중 하나입니다.



2. JavaScript vs TypeScript

현대 프로그래밍 언어에서 TypeScript와 JavaScript의 관계는 꽤 독특합니다. TypeScript는 JavaScript 위에 추가된 레이어로, JavaScript의 기능을 제공하면서 추가적인 타입 시스템을 갖추고 있습니다.

JavaScript는 string, number, object, undefined 같은 기본 타입을 가지고 있지만, 코드 전체에서 일관되게 타입이 사용되었는지 미리 확인해 주지 않습니다. TypeScript는 이런 점을 해결하기 위해 존재합니다.

따라서 기존의 JavaScript 코드는 그대로 사용 가능하지만, TypeScript의 타입 검사기를 사용하면 코드에서 의도와 실제 동작 사이의 차이를 미리 발견할 수 있습니다.

1) TypeScript 의 타입 검사

a. TS와 JS 타입 검사 비교

  • JavaScript: 동적 타입 언어로, 타입 검사가 런타임에 이루어집니다. 컴파일 시점에는 타입 오류를 잡아내지 못합니다.
  • TypeScript: 정적 타입 언어로, 컴파일 시점에서 타입 검사를 수행하여 타입 오류를 사전에 방지합니다.

b. 예제 코드 비교

  • JavaScript 예제
    JavaScript에서는 타입 검사가 런타임에 이루어지므로, 잘못된 타입이 전달되면 런타임 오류가 발생합니다.
function greet(name) {
    if (typeof name !== 'string') {
        throw new Error('Name must be a string');
    }
    return `Hello, ${name}!`;
}

try {
    console.log(greet('Alice'));  // Hello, Alice!
    console.log(greet(42));       // Error: Name must be a string
} catch (error) {
    console.error(error.message);
}
  • greet 함수는 name 인수가 문자열인지 확인하고, 문자열이 아니면 런타임에 오류를 던집니다.
  • greet(42) 호출 시, 런타임에 오류가 발생합니다.

  • TypeScript 예제
    TypeScript에서는 타입을 명시하여 컴파일 시점에 타입 오류를 잡아냅니다.
function greet(name: string): string {
    return `Hello, ${name}!`;
}

console.log(greet('Alice'));  // Hello, Alice!
console.log(greet(42));       // Compile-time error: Argument of type 'number' is not assignable to parameter of type 'string'.
  • greet 함수는 name 인수가 문자열임을 타입으로 명시합니다.
  • greet(42) 호출 시, 컴파일러가 타입 오류를 감지하여 컴파일 시점에 오류를 발생시킵니다.

위와 같이 TypeScript를 사용하면 타입 시스템을 통해 컴파일 시점에 더 많은 오류를 잡아낼 수 있습니다. 이는 코드의 안전성을 높이고, 유지보수를 용이하게 합니다. JavaScript는 동적 언어로 유연하지만, 타입 관련 오류를 런타임에 처리해야 하므로, TypeScript의 정적 타입 시스템을 사용하면 더 많은 오류를 예방할 수 있습니다.



3. TypeScript 설치

1) Node.js 설치

  • https://nodejs.org/en
  • 터미널에서 node -v 입력 후 node의 버전이 출력되면 설치가 된 것입니다.

2) 프로젝트마다 TypeScript 설치

TypeScript 설치 링크 에서 설치를 진행합니다.

프로젝트마다 TypeScript를 설치하고 싶다면 npm install typescript --save-dev를 입력합니다


3) 글로벌로 설치하기

전역으로 TypeScript를 설치하고싶다면 npm install -g typescript 를 입력합니다. 설치가 잘 되었는지 확인하고 싶다면 터미널에서 tsc -v 를 입력해봅니다. 버전이 출력되면 설치가 잘 된것입니다.

컴파일이 잘 동작하는지 간단한 코드를 작성해서 확인해보겠습니다. test 폴더 생성 → index.ts 파일 생성 후 아래 코드를 작성해줍니다.

function hello(name: string) {
  console.log(`Hello ${name}`);
}
hello("TypeScript");

터미널에 tsc index.ts를 입력하면 자동으로 index.js 파일이 test 폴더에서 생성됩니다. 이제 node index.js 를 터미널에 입력하면 ‘Hello TypeScript’가 출력됩니다.



4. TypeScript 동작 원리

1)대다수의 프로그래밍 언어는 어떻게 동작할까?

타입스크립트 동작 방식을 정확히 이해 하려면 대다수의 프로그래밍 언어들이 어떻게 동작 하는지 그 원리를 살펴볼 필요가 있습니다.

먼저 대부분의 프로그래밍 언어는 사실 컴퓨터보단 인간에게 더 친화적입니다. 컴퓨터는 인간과는 달리 바이트코드나 기계어, 이진수 같은 아주 단순한 형태의 언어를 기반으로 동작해요 따라서 영어의 문법과 비슷한 프로그래밍 언어를 컴퓨터가 바로 이해하고 실행할수는 없습니다.

그래서 컴퓨터는 우리가 작성한 코드를 실행하기 위해서 이 코드를 자기가 해석하기 쉬운 형태로 변환 하는 데요 이 과정을 우리는 변환한다 라고 해서 컴파일이라고 부릅니다.

그래서 우리가 프로그래밍 언어로 작성한 코드를 컴파일 하면 코드가 컴퓨터가 이해할 수 있는 기계어 같은 형태로 변환됩니다. 그럼 이제 컴퓨터가 이걸 읽어서 실행하고 결과적으로 코드가 실행되는거죠

그리고 이렇게 코드를 컴파일하는 녀석을 특별히 컴파일러 라고 부릅니다. 컴파일 하는 친구 라는 뜻이죠?
자바나 자바스크립트같은 언어를 컴파일하면 바이트 코드라는 형식으로 변환됩니다. 그래서 설명 편의상 앞으로 컴파일 결과 생성되는 컴퓨터가 이해할 수 있는 형태의 코드를 그냥 바이트코드라고 부르겠습니다

우선 컴파일러는 우리가 작성한 코드를 바로 바이트코드로 변환하는게 아니라 그 전에 AST(추상 문법 트리)라는 특별한 형태로 먼저 변환합니다. AST는 추상 문법 트리 라는 뜻인데요

다음 그림처럼 코드의 공백이나 주석 탭 등의 코드 실행에 관계없는 그런 요소들은 전부 제거하고 트리 형태의 자료구조에 코드를 쪼개서 저장 해 놓은 그런 형태를 말합니다.

왼쪽의 자바스크립트 코드를 AST 추상 문법 트리로 변환하면 오른쪽 처럼 바뀝니다. 물론 정확하게 이렇게 생겼다고 보기에는 조금 어렵구요 대충 이렇게 생겼다 라고 생각해주시면 됩니다.

이렇게 코드를 AST로 변환하고 나면 이제 마지막으로 컴파일러가 AST를 바이트코드로 변환하고 컴파일이 종료됩니다.

자 그래서 우리의 코드가 실행되는 과정을 정리하면 먼저 코드를 컴파일러가 AST로 변환하고 AST를 다시 바이트코드로 변환하고 이렇게 변환된 바이트코드를 컴퓨터가 실행하게 되는거죠


2) 타입 시스템(Type System)?

  • 타입 시스템은 데이터의 종류를 구분하는 체계를 의미합니다.
    • 타입 시스템은 다양한 데이터 유형을 명확하게 분류합니다. 예를 들어, 정수, 문자열, boolean 값 등과 같이 데이터의 종류를 구분합니다.
  • 이 시스템은 데이터가 메모리에 어떻게 저장되고, 어떻게 처리되어야 하는지에 대한 규칙을 정의합니다.
    • 타입 시스템은 데이터가 메모리에 저장되는 방식과 데이터 처리 방식을 규정합니다. 예를 들어, 숫자는 특정 비트 수로 저장되고, 문자열은 문자 배열로 저장됩니다. 이러한 규칙은 데이터의 올바른 사용을 보장합니다.
  • 타입 시스템의 가장 큰 목적은 프로그램의 안정성과 신뢰성을 높이는 것입니다.
    • 타입 시스템은 프로그램의 오류를 사전에 방지하여 안정성과 신뢰성을 높입니다. 올바른 타입 사용을 강제하여, 개발자가 실수로 잘못된 타입을 사용하는 것을 방지하고, 코드의 정확성을 보장합니다. 이로 인해 프로그램이 예상치 못한 동작을 하는 것을 막고, 유지보수가 용이합니다.


3) 타입 안정성 (Type Safety)

타입 안정성은 변수나 함수가 예상된 타입의 값을 갖도록 보장하는 것입니다. 이를 통해 많은 런타임 오류를 컴파일 시점에 방지할 수 있습니다.

//예제
function add(a: number, b: number): number {
    return a + b;
}

console.log(add(5, 10));  // 15
console.log(add(5, 'hello'));  // Compile-time error: Argument of type 'string' is not assignable to parameter of type 'number'.

위 코드에서 add 함수는 ab가 숫자 타입일 것을 명시하고 있습니다. 숫자가 아닌 문자열을 전달하면 컴파일 오류가 발생합니다.


4) 타입 추론 (Type Inference)

타입스크립트는 변수나 함수의 반환 타입을 명시하지 않아도 타입을 추론할 수 있습니다. 이는 코드의 간결성을 유지하면서도 타입 안전성을 제공하는 데 도움을 줍니다.

//예제

let x = 10;  // TypeScript infers x as a number
x = 20;  // No error
x = 'hello';  // Compile-time error: Type 'string' is not assignable to type 'number'

function greet(name = 'World') {
    return `Hello, ${name}!`;
}

let message = greet();  // TypeScript infers message as a string

위 코드에서, x는 처음에 숫자로 초기화되었기 때문에 number 타입으로 추론됩니다. greet 함수의 반환 타입도 자동으로 string으로 추론됩니다.


5) 정적 타입 vs 동적 타입 (Static Types vs Dynamic Types)

정적 타입 언어에서는 변수의 타입을 컴파일 시점에 검사합니다. 반면, 동적 타입 언어에서는 런타임에 타입을 검사합니다.

  • TypeScript (정적 타입)
//예제
let num: number = 5;
num = 'hello';  // Compile-time error: Type 'string' is not assignable to type 'number'

TypeScript는 정적 타입을 사용하여 변수의 타입을 미리 지정하고, 잘못된 타입 할당을 컴파일 시점에 방지합니다.

  • JavaScript (동적 타입)
//예제
let num = 5;
num = 'hello';  // No error, but may cause runtime errors elsewhere

JavaScript는 동적 타입을 사용하여 변수의 타입이 런타임에 결정됩니다.


6) 제네릭 (Generics)

제네릭은 다양한 타입에서 동작할 수 있는 재사용 가능한 컴포넌트를 만들기 위해 사용됩니다. 제네릭을 사용하면 코드의 타입 안정성을 유지하면서도 유연성을 높일 수 있습니다.

//예제
function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>('hello');  // Explicit type argument
let output2 = identity<number>(10);  // Explicit type argument

let output3 = identity('world');  // TypeScript infers type as string
let output4 = identity(20);  // TypeScript infers type as number

위 코드에서 identity 함수는 제네릭 타입 T를 사용합니다. 호출할 때 타입을 명시적으로 지정하거나, TypeScript가 타입을 추론하도록 할 수 있습니다.

TypeScript의 타입 시스템은 코드의 안전성과 유지보수성을 크게 향상시킵니다. 타입 안정성을 통해 예상된 타입의 값을 보장하고, 타입 추론을 통해 코드의 간결성을 유지하며, 정적 타입을 통해 컴파일 시점에 오류를 방지합니다. 제네릭을 사용하면 다양한 타입에서 재사용 가능한 유연한 코드를 작성할 수 있습니다. 이러한 기능들을 통해 TypeScript는 JavaScript보다 더욱 안정적이고 견고한 코드를 작성할 수 있도록 도와줍니다.



5. 컴파일러 환경 설정

1) tsconfig.json

‘tsconfig.json’ 파일은 TypeScript 컴파일러(tsc)에 대한 설정을 정의하는 데 사용됩니다. 이 파일을 통해 프로젝트의 컴파일 옵션을 구성하고, 포함할 파일과 제외할 파일 등을 지정할 수 있습니다.

npm i --save-dev typescript

  • tsconfig.json 파일 생성
tsc --init 
  • tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

  • target : 이 속성은 컴파일된 JavaScript의 ECMAScript 버전을 설정합니다. ‘es2016’ 설정되어 있으므로 ES2016으로 컴파일됩니다.

  • module : 이 속성은 코드 생성 방식을 설정합니다. 여기서는 ‘commonjs’ 로 설정되어 있어 Node.js 와 호환되는 CommonJS 형태의 모듈 코드를 생성합니다.

  • esModuleInterop : 이 속성은 ES 모듈과 CommonJS 모듈 간의 상호 운용성을 활성화하는 옵션입니다. true로 설정되어 있으면 ES 모듈과 CommonJS 모듈을 상호 운용할 수 있습니다.

  • forceConsistentCasingInFileNames : ****이 속성은 파일 이름에서 대소문자가 일관되게 사용되도록 강제하는 옵션입니다. true로 설정되어 있으면 파일 이름의 대소문자가 일치하지 않는 경우 컴파일러가 경고를 발생시킵니다.

  • strict : 이 속성은 엄격한 타입 검사를 활성화하는 옵션입니다. true 로 설정되어 있으면 TypeScript 컴파일러가 더 엄격한 타입 검사를 수행합니다.

  • skipLibCheck : 이 속성은 라이브러리 검사를 건너뛰는 옵션입니다. true로 설정되어 있으면 컴파일 시 라이브러리의 검사를 건너뛰고 빠르게 컴파일할 수 있습니다. 하지만 이 옵션은 타입 안정성에 영향을 줄 수 있으므로 주의해야 합니다.

  • outDir: TypeScript 컴파일러가 컴파일된 JavaScript 파일을 저장할 디렉토리를 지정합니다. 이 속성은 컴파일된 JavaScript 파일들이 위치할 디렉토리 경로를 설정합니다. 현재 ‘outDir’ 이 ‘dist’ 로 설정되어 있으므로 TypeScript 소스 파일들이 컴파일되어 생성된 JavaScript 파일들은 ‘dist’ 디렉토리에 저장됩니다.

    {
      "compilerOptions": {
        ```
        "outDir": "dist"
      }
    }

    컴파일 결과 dist 폴더가 생성되고 index.js 파일이 생성되었습니다.

  • include : ‘include’ 속성은 TypeScript 컴파일러에게 어떤 파일을 컴파일할 것인지를 명시하는 역할을 합니다. 해당 설정은 src 디렉토리의 모든 하위 디렉토리 내의 모든 파일을 컴파일 대상으로 지정합니다.

      {
        "compilerOptions": {
          ```
        },
        "include": ["src/**/*"]
      }
  • noUncheckedIndexedAccess : 디폴트 값은 false 입니다. 해당 속성의 값을 true로 설정한다면 배열이나 객체의 속성에 접근할 때 해당 속성이 존재하지 않을 가능성을 고려하도록 강제하는 옵션입니다. 이 속성을 활성화하면 예시를 들어 설명해보겠습니다.

    const nums: number[] = [];
    const a = 10 + nums[0]; // error

    nums 배열은 현재 빈 배열인데 인덱스0의 값에 접근하려고 하니 에러가 발생합니다. 해당 속성을 false로 설정하면 에러가 사라집니다.

  • lib : 이 속성은 TypeScript 컴파일러가 사용할 라이브러리 파일들을 지정하는 데 사용됩니다. 컴파일 시 포함될 JavaScript 표준 라이브러리의 버전을 명시합니다. 또한 배열 형태이다 보니 라이브러리 옵션을 여러개 지정할 수 있습니다.

    {
      "compilerOptions": {
        "lib": ["ES5"]
      }
    }

    해당 코드는 TypeScript 컴파일러가 ES5 표준 라이브러리를 사용하도록 설정하는 것입니다. 따라서 ES5에 맞지 않는 문법을 사용했을 때 에러가 발생합니다.



6. TypeScript 기본 타입

TypeScript의 기본 타입을 사용하면 변수의 타입을 명확히 정의하여, 코드의 안정성과 가독성을 높일 수 있습니다. 각 기본 타입 string, number, boolean, null, any는 특정한 종류의 데이터를 나타내며, 이를 통해 프로그램이 예상대로 동작하도록 보장합니다.

1) string

문자열 타입으로, 텍스트 데이터를 나타냅니다.

let name: string = 'Alice';
console.log(name);  // Alice

2) number

숫자 타입으로, 정수와 부동 소수점 숫자를 모두 포함합니다.

let age: number = 30;
console.log(age);

3) boolean

boolean 타입으로, 참(true) 또는 거짓(false) 값을 가집니다.

let isStudent: boolean = true;
console.log(isStudent);  // true

4) null

null 타입으로, 값이 없음을 나타냅니다.

let emptyValue: null = null;
console.log(emptyValue);  // null

5) any

모든 타입을 허용합니다. 주로 타입 검사를 피하고 싶을 때 사용합니다. 하지만, 타입 안전성을 떨어뜨릴 수 있으므로 주의가 필요합니다.

let variable: any = 'Hello';
console.log(variable);  // Hello

variable = 42;
console.log(variable);  // 42

variable = true;
console.log(variable);  // true

profile
UI/UX디자이너의 코딩 공부

0개의 댓글