우아한 타입스크립트 스터디 6장 - 타입스크립트 컴파일

우아한 타입스크립트 with 리액트 6장 - 타입스크립트 컴파일

개요

6장은 타입스크립트 컴파일러의 동작 원리와 컴파일 과정을 상세히 다룹니다. 타입스크립트가 어떻게 자바스크립트로 변환되는지, 언제 타입 검사가 이루어지는지, 그리고 컴파일러의 내부 구조를 이해할 수 있는 내용으로 구성되어 있습니다.


6.1 자바스크립트의 런타임과 타입스크립트 컴파일

6.1.1 런타임과 컴파일 타임

언어 분류

  • 고수준 언어: 사람이 이해하기 쉬운 형식 (JavaScript, TypeScript)
  • 저수준 언어: 컴퓨터가 이해하기 쉬운 형식 (기계어, 바이트코드)

컴파일 과정

개발자 소스코드 작성 → 컴파일러에 의해 기계어 코드로 변환 → 실행 가능한 프로그램
  • 컴파일 타임: 소스코드가 컴파일 과정을 통해 기계어 코드로 변환되어 실행할 수 있는 프로그램이 되는 과정
  • 런타임: 컴파일이 완료된 프로그램이 메모리에 적재되어 실행되는 시간

6.1.2 자바스크립트의 런타임

자바스크립트 런타임 특징

  • 자바스크립트 실행 환경을 의미 (브라우저, Node.js)
  • 대표적인 인터프리터 언어이지만 내부적으로 컴파일 단계 존재
  • V8 엔진은 성능 최적화를 위해 컴파일 단계를 거쳐 코드를 캐싱

런타임 에러

  • 자바스크립트는 실행 도중 에러가 발생할 수 있음
  • 런타임에서만 타입 오류를 발견할 수 있음

6.2 타입스크립트 컴파일 과정

6.2.1 컴파일과 트랜스파일

타입스크립트 컴파일의 특징

  • 고수준 언어(TS)에서 고수준 언어(JS)로 변환
  • 일반적인 컴파일과 구분하여 **트랜스파일(Transpile)**이라고도 함
  • 하지만 넓은 의미에서 컴파일이라고 통용됨

6.2.2 타입스크립트 컴파일러 동작 과정

전체 컴파일 과정

컴파일 타임 (tsc)

  1. TypeScript 소스코드TypeScript AST 변환
  2. 타입 검사기가 AST를 확인하여 타입 검사
  3. TypeScript ASTJavaScript 소스 변환

런타임 4. JavaScript 소스JavaScript AST 변환 5. AST바이트 코드 변환 6. 런타임에서 바이트 코드 실행

6.2.3 타입 정보의 생명주기

중요한 특징

  • 타입스크립트 소스코드의 타입은 1~2단계에서만 사용
  • 타입 정보는 타입 검사에만 사용되고 최종 프로그램에는 영향 없음
  • 컴파일 후에는 타입이 제거되어 순수한 JavaScript만 남음

런타임에서의 타입 제한

interface Square {
  width: number
}

interface Rectangle extends Square {
  height: number
}

type Shape = Square | Rectangle

function calculateArea(shape: Shape) {
  // ❌ 에러: 'Rectangle'은 타입이므로 값으로 사용 불가
  if (shape instanceof Rectangle) {
    return shape.width * shape.height
  } else {
    return shape.width * shape.width
  }
}

6.3 타입스크립트 컴파일러의 구조

6.3.1 컴파일러의 주요 역할

2가지 핵심 기능

  1. 정적 분석을 통해 코드의 타입 오류 검사
  2. 최신 버전의 TS/JS 코드구버전 JavaScript로 트랜스파일

6.3.2 컴파일러 5단계

1. 스캐너(Scanner)

  • 타입스크립트 소스 파일을 어휘적으로 분석(lexical analysis)
  • 소스코드를 의미 있는 토큰(token) 단위로 분리
  • 예: let, name, =, "John" 등으로 분리

2. 파서(Parser)

  • 토큰 정보를 이용하여 AST(Abstract Syntax Tree) 생성
  • 구문적 분석(syntax analysis) 수행
  • 실질적인 구조를 노드 단위의 트리 형태로 표현

3. 바인더(Binder)

  • 타입 검사를 위한 기반 마련
  • 심볼(Symbol) 데이터 구조 생성
  • AST의 각 노드에 대응하는 선언된 타입의 노드 정보 저장
export interface Symbol {
  flags: SymbolFlags // Symbol flags
  escapedName: string // Name of symbol
  declarations?: Declaration[] // Declarations associated with this symbol
  // ...
}

4. 체커(Checker)

  • AST 노드를 탐색하면서 심볼 정보를 활용
  • 주어진 소스 파일에 대해 타입 검사 진행
  • 타입 오류 발견 및 보고

5. 이미터(Emitter)

  • 타입스크립트 소스 파일을 **JavaScript 소스 파일(.js)**과 **타입 선언 파일(.d.ts)**로 변환
  • 개발자가 설정한 tsconfig.json 읽어와 설정 적용
  • emitFiles 함수를 사용하여 소스 변환 수행

6.3.3 컴파일 과정 요약

1. tsc 명령어 실행 → 프로그램 객체가 컴파일 과정 시작
2. 스캐너 → 소스 파일을 토큰 단위로 분리
3. 파서 → 토큰을 이용하여 AST 생성
4. 바인더 → AST의 각 노드에 대응하는 심볼 생성
5. 체커 → AST를 탐색하면서 심볼 정보를 활용하여 타입 검사
6. 이미터 → 타입 검사 결과 에러가 없다면 JavaScript 소스로 변환

6.4 AST(Abstract Syntax Tree)

6.4.1 AST의 개념

AST란?

  • 컴파일러가 소스코드를 해석하는 과정에서 생성된 데이터 구조
  • 어휘적 분석구문 분석을 통해 소스코드를 노드 단위의 트리 구조로 구성
  • 각 노드는 코드상의 위치, 구문 종류, 코드 내용 등의 정보를 포함

6.4.2 심볼(Symbol) 시스템

심볼의 역할

  • AST의 각 노드에 대응하는 선언된 타입의 노드 정보 저장
  • 타입 검사를 위한 기반 데이터 제공

SymbolFlags 예시

export const enum SymbolFlags {
  None = 0,
  FunctionScopedVariable = 1 << 0,
  BlockScopedVariable = 1 << 1,
  Property = 1 << 2,
  EnumMember = 1 << 3,
  Function = 1 << 4,
  Class = 1 << 5,
  Interface = 1 << 6,
  // ...
}

6.5 타입 검사와 코드 변환의 독립성

6.5.1 독립적인 두 과정

중요한 특징

  • 타입 검사코드 변환은 독립적으로 동작
  • 타입 오류가 있어도 컴파일은 진행됨
  • 이는 개발 과정에서 점진적 마이그레이션을 가능하게 함

6.5.2 정적 타입 검사기

타입스크립트의 특성

  • 컴파일 타임에 타입 검사 수행
  • 에러 발생 시 프로그램 실행 방지
  • 정적 타입 검사기(static type checker) 역할

6.6 실무 활용 팁

개발 도구 활용

  • TypeScript Playground: 스캐너, 파서 플러그인으로 컴파일 과정 시각화
  • TypeScript AST Viewer: AST 구조 확인
  • Symbol 확인 플러그인: 심볼 정보 탐색

컴파일 설정 최적화

  • tsconfig.json에서 적절한 target 옵션 설정
  • 타입 검사와 빌드 성능 균형 맞추기
  • 점진적 마이그레이션 전략 수립

핵심 포인트

  1. 타입스크립트는 컴파일 타임에만 타입 정보 활용
  2. 런타임에서는 타입 정보 접근 불가
  3. 컴파일러는 5단계(스캐너→파서→바인더→체커→이미터)로 동작
  4. 타입 검사와 코드 변환은 독립적 과정
  5. AST와 심볼을 통한 정적 분석 수행