icon
8장 : 타입 선언과 앰비언트 선언

DefinitelyTyped와 @types


타입스크립트를 사용하여 자바스크립트 라이브러리를 개발할 때, 또는 기존 자바스크립트 라이브러리를 타입스크립트 프로젝트에서 활용할 때 가장 중요한 요소 중 하나가 바로 타입 정의 파일(.d.ts) 입니다. 하지만 세상에는 수많은 자바스크립트 라이브러리가 존재하고, 이 모든 라이브러리에 대해 개발자가 직접 .d.ts 파일을 작성하는 것은 비효율적이고 거의 불가능에 가깝습니다.

이러한 문제를 해결하기 위해 등장한 것이 바로 DefinitelyTyped 프로젝트와 npm의 @types 스코프 패키지입니다.


DefinitelyTyped 프로젝트란?

DefinitelyTyped는 수많은 자바스크립트 라이브러리에 대한 고품질의 타입 정의 파일을 제공하는 오픈 소스 프로젝트입니다. 전 세계의 개발자들이 자발적으로 참여하여 각 라이브러리의 .d.ts 파일을 작성하고 유지보수하며, 이를 통해 타입스크립트 사용자들이 자바스크립트 생태계를 타입 안전하게 활용할 수 있도록 돕습니다.

DefinitelyTyped는 GitHub 저장소(https://github.com/DefinitelyTyped/DefinitelyTyped)에서 관리되며, 각 라이브러리별로 별도의 디렉토리에 타입 정의 파일이 존재합니다. 예를 들어, Lodash 라이브러리의 타입 정의는 DefinitelyTyped/types/lodash 경로에 있습니다.


@types 스코프 패키지

DefinitelyTyped에 기여된 모든 타입 정의 파일은 자동으로 npm의 @types 스코프로 패키징되어 배포됩니다. 즉, lodash 라이브러리에 대한 타입 정의는 npm install @types/lodash 명령어로 설치할 수 있게 됩니다.

@types 패키지들은 실제 자바스크립트 코드를 포함하지 않고, 오직 해당 라이브러리의 타입 정의(.d.ts 파일)만을 포함합니다. 타입스크립트 컴파일러는 기본적으로 node_modules/@types 디렉토리를 자동으로 검색하여 필요한 타입 정의 파일을 찾습니다.

사용 예시

lodash 라이브러리를 타입스크립트 프로젝트에서 사용하려고 할 때:

lodash 라이브러리 설치

npm install lodash

lodash에 대한 타입 정의 설치

npm install --save-dev @types/lodash

--save-dev 플래그는 개발 의존성(devDependencies)으로 설치하여, 실제 프로덕션 환경에는 포함되지 않음을 나타냅니다. 타입 정의 파일은 컴파일 시에만 필요하기 때문입니다.

이제 타입스크립트 코드에서 lodash를 가져와 사용하면, 타입스크립트 컴파일러는 node_modules/@types/lodash 경로의 .d.ts 파일을 참조하여 _ 객체의 모든 메서드와 속성에 대한 정확한 타입 정보를 제공합니다.

import _ from 'lodash'; // 'lodash' 모듈을 가져옴 (CommonJS 모듈이므로 esModuleInterop: true 권장)

const numbers = [1, 2, 3, 4, 5];
const sum = _.sum(numbers); // sum은 number 타입으로 추론됩니다. (정확한 매개변수 힌트 제공)
console.log(sum); // 15

const shuffled = _.shuffle(numbers); // shuffled는 number[] 타입으로 추론됩니다.
console.log(shuffled);

// _.sortBy(numbers, 'invalidKey'); // Error: 'string' 형식은 'lodash.ValueIteratee<number>' 형식에 할당될 수 없습니다.
                                  // 타입 정의 덕분에 잘못된 인자 사용 시 오류를 즉시 감지합니다.

@types 패키지의 장점

  • 자동 완성 및 타입 검사: IDE에서 라이브러리 사용 시 정확한 자동 완성(_.)과 함수 시그니처 힌트를 제공하여 개발 생산성을 크게 높입니다. 잘못된 인자 전달이나 존재하지 않는 메서드 호출 등의 오류를 컴파일 시점에 즉시 잡아줍니다.
  • 쉬운 통합: npm install 한 줄로 수많은 자바스크립트 라이브러리를 타입스크립트 프로젝트에 타입 안전하게 통합할 수 있습니다.
  • 커뮤니티 주도: 전 세계 개발자들의 기여로 최신 라이브러리 버전에도 빠르게 대응하고, 버그 수정 및 개선이 활발하게 이루어집니다.
  • 명확한 버전 관리: @types 패키지는 해당 라이브러리의 특정 버전(또는 범위)에 맞는 타입 정의를 제공하므로, 라이브러리 버전과 타입 정의 버전 간의 호환성을 관리하기 용이합니다.

@types 패키지가 없을 때

만약 특정 자바스크립트 라이브러리에 대한 @types 패키지가 존재하지 않는다면, 다음 두 가지 방법 중 하나를 선택할 수 있습니다.

직접 .d.ts 파일 작성: 해당 라이브러리의 외부 API를 파악하여 직접 앰비언트 모듈 선언(.d.ts 파일)을 작성합니다 (8장 3절 참조). 이 방법은 라이브러리의 규모가 작거나, 사용하려는 부분이 제한적일 때 유용합니다.

my-lib-declaration.d.ts
declare module 'my-custom-js-lib' {
  export function doSomething(param: string): number;
}
app.ts
import { doSomething } from 'my-custom-js-lib';
doSomething('hello');

any 타입으로 사용 (최후의 수단): 정의된 타입이 없어 타입 안정성을 포기하고 any 타입으로 라이브러리를 사용하는 방법입니다.

app.ts
import SomeUntypedLib from 'some-untyped-lib'; // 타입 정보가 없으므로 SomeUntypedLib는 any 타입
const lib = new SomeUntypedLib();
lib.doSomethingElse(123); // 타입 검사 없이 허용

이 방법은 타입스크립트 사용의 이점을 상실하므로 가능한 한 피해야 합니다.


라이브러리가 자체적으로 타입 정의를 제공하는 경우

일부 최신 자바스크립트 라이브러리(특히 타입스크립트로 작성된 라이브러리)는 package.json 파일의 types (또는 typings) 필드를 통해 자체적으로 타입 정의 파일을 포함하여 배포합니다.

my-typescript-lib/package.json
{
  "name": "my-typescript-lib",
  "main": "dist/index.js",
  "types": "dist/index.d.ts", // 라이브러리 자체에 타입 정의 포함
  // ...
}

이러한 라이브러리들은 @types 패키지를 별도로 설치할 필요가 없습니다. npm으로 라이브러리를 설치하면 타입스크립트 컴파일러가 package.jsontypes 필드를 참조하여 자동으로 타입 정의를 찾습니다.

정리

  • 라이브러리가 자체 types 필드를 가짐: @types 설치 필요 없음.
  • 라이브러리가 자체 types 필드를 가지지 않음: @types/<라이브러리명> 설치 시도.
  • @types에도 없음: 직접 .d.ts 파일 작성 또는 any 사용.

tsconfig.jsontypestypeRoots 옵션

tsconfig.json 파일의 compilerOptions에서 typestypeRoots 옵션을 사용하여 타입 정의 파일의 검색 방식을 더 세밀하게 제어할 수 있습니다.

  • typeRoots: node_modules/@types와 같이 타입 정의 파일을 검색할 루트 디렉토리 목록을 지정합니다. 기본적으로 node_modules/@types가 포함되어 있으므로, 대부분의 경우 명시할 필요는 없습니다. 하지만 @types가 아닌 특정 커스텀 타입 정의 경로를 추가하고 싶을 때 사용합니다.
    "compilerOptions": {
      "typeRoots": ["./node_modules/@types", "./custom-types"] // custom-types 디렉토리도 검색
    }
  • types: 컴파일러가 전역 타입 선언으로 포함할 @types 패키지 목록을 지정합니다. 이 옵션이 없으면 typeRoots에 있는 모든 @types 패키지가 자동으로 포함되지만, types를 명시하면 여기에 나열된 패키지만 포함됩니다.
    "compilerOptions": {
      "types": ["node", "jest"] // 오직 @types/node와 @types/jest만 포함하고 싶을 때
    }
    이는 번들링 크기를 줄이거나, 불필요한 전역 타입 충돌을 피하고 싶을 때 유용합니다.

DefinitelyTyped와 @types는 타입스크립트 생태계의 핵심적인 부분이며, 자바스크립트와 타입스크립트 간의 호환성을 보장하는 가장 중요한 메커니즘입니다. 이를 통해 수많은 기존 자바스크립트 라이브러리를 타입 안전하게 활용할 수 있게 되어, 타입스크립트의 도입 장벽을 크게 낮추고 개발 생산성을 향상시키는 데 기여합니다. 새로운 라이브러리를 사용할 때는 항상 @types 패키지의 존재 여부를 먼저 확인하는 습관을 들이는 것이 좋습니다.