노트

선언 파일(.d.ts)과 declare

Declaration Files

프런트엔드#ts · 연결된 개념 5개

쉽게 말하면

선언 파일은 수입 제품에 붙이는 한글 설명서 스티커예요. 제품인 JS 코드는 그대로 두고 TypeScript가 읽을 수 있게 모양만 적어 줘서, JS 라이브러리를 타입 에러 없이 쓸 수 있죠.

비유가 깨지는 곳 설명서는 제품을 검사하지 않아요. declare는 어딘가에 있다는 약속일 뿐이라 틀리게 적어도 컴파일은 통과하고 런타임에 깨져요. 그래서 먼저 @types 패키지나 라이브러리가 같이 배포한 .d.ts를 찾아요.

선언 파일(Declaration File, .d.ts)은 실행 코드 없이 타입 정보만 담은 파일이다. JavaScript로 작성된 라이브러리나 전역 값의 모양을 TypeScript에게 알려 준다.

  • JS 라이브러리를 import했는데 타입 에러가 나면, 먼저 커뮤니티 타입 패키지를 찾는다: npm i -D @types/lodash. DefinitelyTyped 저장소에서 관리된다
  • 요즘 라이브러리는 패키지 안에 .d.ts를 같이 배포하는 경우가 많다. 직접 라이브러리를 만들면 tsconfig의 declaration: true로 생성한다(tsconfig 핵심 옵션)
  • HTML(HyperText Markup Language)의 <script>나 빌드 도구가 주입한 전역 변수처럼 TS가 모르는 값은 declare로 존재만 알린다
declare const __APP_VERSION__: string      // 빌드 때 치환되는 전역
declare module '*.svg' {                   // 확장자 import의 타입
  const src: string
  export default src
}
  • declare는 "어딘가에 있다"는 약속일 뿐 검증하지 않는다. 틀리게 적으면 런타임에 깨진다
  • 기존 전역 타입을 늘릴 때는 interface의 선언 병합(Declaration Merging)을 쓴다(type과 interface)
  • 모듈 시스템과의 관계는 ES 모듈과 CommonJS. 타입으로 적은 계약 밖의 동작에도 사용자가 의존하게 된다는 점은 하이럼의 법칙

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 선언형과 명령형 프로그래밍

    명령형(Imperative)·절차적(Procedural) 프로그래밍은 결과에 도달하는 방법(how)을 단계별로 지시하고, 선언형 프로그래밍(Declarative Programming)은 원하는 결과(what)만 기술하고 과정은 도구에 맡긴다. 길 안내로 치면 "직진하다 두 번째 신호에서 우회전"이 명령형, "강남역 가 주세요"가 선언형이다.

  • TypeScript 데코레이터

    데코레이터(Decorator)는 클래스나 그 멤버 선언 앞에 @표현식을 붙여, 정의 시점에 대상을 감싸거나 메타데이터를 등록하는 문법이다. 기존 코드를 고치지 않고 기능을 덧붙인다는 점에서 데코레이터 패턴과 생각이 같다.

  • verbatimModuleSyntax와 import type

    verbatimModuleSyntax(TypeScript 5.0+)는 import/export를 쓴 그대로 출력에 남기라고 강제하는 컴파일러 옵션이다. 대신 타입만 가져오는 import에는 type을 직접 표시해야 한다. import type으로 표시한 것만 지워진다.

  • enum과 as const 객체

    TypeScript의 enum은 관련된 상수 집합에 이름과 타입을 함께 주는 문법이다. 다른 TS 타입과 달리 런타임 객체로 컴파일되어 남는다. 요즘 프런트엔드에서는 같은 일을 as const 객체와 유니언 타입으로 하는 경우가 많다.

  • tsc --noEmit과 타입 검사 분리

    --noEmit은 tsc에게 타입 검사만 하고 JavaScript 파일은 만들지 말라고 하는 옵션이다. 오류가 있으면 0이 아닌 종료 코드로 실패하고, 없으면 조용히 끝난다.

보기 옵션