[TypeScript] Effective TS - item.03 - 코드 생성과 타입 체크는 무관

Date:

카테고리:

태그:

1. TS 컴파일러의 두 가지 역할

  • 호환성을 위해 최신 TS/JS를 구버전의 JS로 트랜스파일
  • TS 코드의 타입 오류를 체크
  • 두 역할은 서로 독립적으로 작동

2. 타입 오류가 있어도 컴파일 가능

  • 타입 오류가 있어도 컴파일 된 산출물이 있는 것이 다른 부분 확인에 도움됨
  • 오류 존재 시 컴파일 하지 않는 옵션 있음(noEmitOnError)

3. 런타임에는 타입 체크가 불가능

  • 아래 4가지 예시를 통해 런타임에서의 타입 체크 이해
  • interface인 Square와 Rectangle을 구분하는 사례

  • 타입 관련 코드는 컴파일 시 제거 되 체크가 불가능

    // 타입 관련 내용은 컴파일 시 제거 됨 (interface, type 등)
    // (= 컴파일 된 JS 파일에는 존재하지 않게 됨)
    interface Square {
      width: number
    }
    interface Rectangle extends Square {
      height: number
    }
    type Shape = Square | Rectangle
    
    function calculateArea(shape: Shape) {
      // interface인 조건문의 Rectangle은 제거 되어 비교 불가
      if (shape instanceof Rectangle) {
        (...)
      }
    }
    
  • 만약 위 예시에서 타입 확인을 하고 싶다면 속성을 확인해야함

    (...)
    function calculateArea(shape: Shape) {
      // 해당 객체에 height라는 속성이 있는지 직접 확인
      if ('height' in shape) {
        (...)
      }
    }
    
  • 런타임에 접근가능한 타입 정보를 저장하는 ‘태그’ 기법

    interface Square {
      kind: 'square'
      (...)
    }
    interface Rectangle extends Square {
      kind: 'rectangle'
      (...)
    }
    type Shape = Square | Rectangle
    
    function calculateArea(shape: Shape) {
      // 명시적으로 타입 정보를 저장하는 kind 속성을 통해 구분
      if (shape.kind === 'rectangle') {
        (...)
      }
    }
    

3. 타입 연산은 런타임에 영향을 주지 않음

// (TS 코드)
// Type Assertion 으로 반환되는 val의 타입을 숫자로 강제함
function asNumber(val: number | string): number {
  return val as number
}

// (JS 코드 - 트랜스파일링 됨)
// 타입 코드 제거 됨 => 타입과 무관하게 val 반환
function asNumber(val) {
  return val
}

// (TS 코드 - 의도에 맞게 수정 됨)
function asNumber(val: number | string): number {
  return Number(val)
}

Type Assertion 추가 설명글 링크

4. 런타임 타입은 선언 타입과 다를 수 있음

// 아래 함수는 파라미터가 boolean으로 들어옴
// TS 자체로는 default 케이스로 넘어가는 경우가 없음
function threeCase(value: boolean) {
  switch (value) {
    case true:
      console.log("case: true");
      break;
    case false:
      console.log("case: false");
      break;
    default:
      console.log("case: default");
  }
}

// 그러나 API 요청의 응답이 boolean이 아닐 경우
// 예외적으로 default 케이스로 넘어갈 수도 있음
interface ApiResponse {
  value: boolean;
}
async function apiCode() {
  const response = await fetch("/case");
  const result: ApiResponse = await response.json();
  threeCase(result.value);
}

5. TS의 타입으로는 함수 오버로드 불가

  • TS의 함수 오버로딩은 타입 수준에서만 작동
  • TS에서는 하나의 함수에 하나의 구현체만 허용 (타입 선언은 여러개 가능)
  • 함수 오버로딩: 매개변수만 다른 여러 버젼의 함수 사용

    // TS설정: {"noImplicitAny":false}
    
    // 아래 두 줄은 컴파일 시에는 제거 됨
    function add(a: number, b: number): number
    function add(a: string, b: string): string
    
    function add(a, b) {
      return a + b
    }
    
    const three = add(1, 2) // Type is number
    const twelve = add('1', '2') // Type is string
    

5. TS의 타입은 런타임 성능에 영향 없음

  • 타입 코드는 트랜스파일링시 제거 => 성능과 무관
  • TS의 컴파일 속도는 상당히 빠른 편이나
  • 컴파일 오버헤드가 커질 시 타입체크를 생략하고 트랜스파일만 하는 옵션도 존재
  • 오버헤드: 어떤 처리에 드는 간접적 시간 및 메모리

TypeScript 카테고리 내 다른 글 보러가기

댓글 남기기