타입스크립트 컴파일러(tsc)의 타입 검사 프로세스

프로젝트 빌드 시에 작동되는 타입스크립트 컴파일러에 대해 알아보자.

TypeScript 컴파일러(tsc)

tsc의 역할은 두가지다.

1. 트랜스파일링

TypeScript 코드를 JavaScript로 변환해 브라우저나 Node.js에서 실행 가능하게 만든다.

2. 타입 검사

정적 타입 시스템을 기반으로 코드의 타입 오류를 컴파일 타임에 미리 찾아내, 런타임에서 발생할 수 있는 오류를 사전에 방지한다.

TypeScript 타입 시스템

타입 추론과 명시적 타입 지정

타입 추론

let name = "Alice"; // 타입스크립트가 자동으로 string으로 추론

명시적 타입 지정

// 명시적 타입 지정
let isVisible: boolean = true;

구조적 타입 시스템

타입의 이름 이 아니라, 형태 가 같으면 같은 타입으로 간주하는 방식

type Point = { x: number, y: number };

function printPoint(p: Point) {
  console.log(`x: ${p.x}, y: ${p.y}`);
}

const coord = { x: 10, y: 20, z: 30 }; // z가 있어도 무관
printPoint(coord); // 구조가 맞으면 허용됨

coord는 Point 타입과 이름은 다르지만, 필요한 구조(x, y)를 만족하기 때문에 함수에 전달이 가능

(명목적 타입 시스템을 쓰는 언어(C#, Java 등)는 타입 이름이 일치해야만 동일한 타입으로 인정)

프로젝트 빌드·배포 관점에서의 개발 사이클

  • Compile: TypeScript 코드를 JavaScript로 변환하고, 타입 검사가 수행된다.
  • Bundle: 타입 검사가 끝난 .js 파일을 하나의 큰 번들로 합치거나 최적화한다. (번들러가 수행)
  • Deploy: 최종 타입 체크, CI/CD에서 배포 전에 검사하는 단계 (tsc --noEmit 명령으로 타입 검사만 수행하고, 오류 없으면 배포)

타입 검사는 주로 Compile 단계에서 수행, 나머지 단계에서는 보조적으로 확인

TypeScript AST(추상 구문 트리)

타입스크립트 컴파일러는 코드의 구조를 이해하기 위해 추상구문트리를 만든다.

AST란?

AST는 소스 코드를 트리 형태의 구조적 표현으로 바꾼 것이다. 문법 요소들이 어떤 방식으로 구성되어 있는지를 나타내며, 타입 검사의 기초가 된다.

AST 생성 과정

Scanner와 parser을 사용해 컴파일 과정에 각 구문을 토큰으로 추출하여 AST로 변환하기까지의 역할을 수행한다.

ts파일 => scanner => 토큰들로 분리 => parser => AST

  • Scanner: ts로 입력된 코드 문자열을 let, =, number 같은 토큰으로 분리한다.
  • Parser: 토큰들을 조합해 문법 구조를 인식하고, 트리 형태인 AST를 만든다. 또한 문법 오류가 있는지 분석해 알려주는 역할도 한다.

타입 검사

Binder (AST와 심볼(Symbol)을 연결)

이 AST 노드가 어떤 심볼에 해당하는지를 분석해서 심볼 테이블에 등록하는 역할

function greet(name: string) { ... }

이 코드를 파싱하면 AST 상에는 FunctionDeclaration 노드가 생기고, Binder는 이 노드에서 "greet"라는 이름을 추출해 심볼 테이블에 등록한다. (코드 내의 식별자(변수, 함수, 클래스 등) 를 추적하기 위해)

  1. 선언(let, function, class 등)을 심볼로 바꾸고
  2. 이 심볼들을 해당 스코프(전역/지역/모듈 등) 에 연결하며
  3. type checker가 타입을 체크할 수 있도록 준비해주는 것

(cf. 심볼 테이블 구조 덕분에 타입스크립트는 빠르게 특정 식별자의 타입을 찾아서 추론하거나 검사할 수 있다.)

type checker(타입 일치 여부 검사)

Binder가 심볼 테이블을 완성한 후, 본격적으로 타입 검사하는 도구

Type Checker 동작 방식

  • AST를 순회하면서 모든 표현식과 타입 주석을 탐색
  • 각 노드에 해당하는 타입을 계산하거나 추론
  • 타입 간의 호환성 검사 수행 (string, number 등)
  • 불일치하는 타입이 있으면 에러(Diagnostic)로 수집

타입 검사 과정 요약

[1] AST 생성 ↓ [2] Binder

  • 선언을 심볼로 만들고
  • 심볼 테이블(HashMap)에 등록 ↓

[3] Type Checker

  • AST를 따라 타입 추론 & 검사
  • 심볼 테이블에서 타입 정보 참조
  • 오류 발생 시 Diagnostic 수집