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

타입 선언 파일 작성 및 사용


앞서 8장 1절에서 .d.ts 파일이 무엇이고 왜 필요한지, 그리고 declare 키워드의 기본적인 사용법을 알아보았습니다. 이번 절에서는 실제 시나리오를 바탕으로 타입 선언 파일(.d.ts)을 어떻게 작성하고 프로젝트에서 사용하는지 구체적인 예시와 함께 살펴보겠습니다.


시나리오: 자바스크립트 유틸리티 라이브러리에 타입 추가하기

우리는 이미 존재하는 간단한 자바스크립트 유틸리티 파일이 있다고 가정하고, 이 파일에 타입스크립트의 타입 정보를 추가하는 .d.ts 파일을 작성해볼 것입니다.

자바스크립트 파일 (src/js/StringUtils.js)

src/js/StringUtils.js
// 이 파일은 CommonJS 모듈로 작성되었다고 가정합니다.

/**
 * 주어진 문자열의 첫 글자를 대문자로 변환합니다.
 * @param {string} str - 원본 문자열
 * @returns {string} 첫 글자가 대문자로 변환된 문자열
 */
function capitalize(str) {
  if (typeof str !== 'string' || str.length === 0) {
    return '';
  }
  return str.charAt(0).toUpperCase() + str.slice(1);
}

/**
 * 주어진 문자열이 비어있는지 (null, undefined, 빈 문자열) 확인합니다.
 * @param {string | null | undefined} str - 확인할 문자열
 * @returns {boolean} 비어있으면 true, 아니면 false
 */
function isEmpty(str) {
  return str === null || str === undefined || str.length === 0;
}

module.exports = {
  capitalize,
  isEmpty
};

이 자바스크립트 파일은 capitalizeisEmpty라는 두 함수를 CommonJS 방식으로 내보냅니다. 타입스크립트 프로젝트에서 이 함수들을 import하여 사용할 때, 타입 정보가 없으면 any로 추론되어 타입 검사의 이점을 누릴 수 없습니다.


타입 선언 파일 작성하기 (.d.ts)

이제 위 StringUtils.js 파일에 대한 타입 정보를 담은 StringUtils.d.ts 파일을 작성해봅시다. 이 파일은 src/js 폴더와 동일한 레벨에 생성하거나, 별도의 types 또는 @types 폴더에 생성할 수 있습니다. 여기서는 src/js/StringUtils.d.ts로 생성하겠습니다.

타입 선언 파일 (src/js/StringUtils.d.ts)

src/js/StringUtils.d.ts
// 이 파일은 'StringUtils'라는 CommonJS 모듈에 대한 타입 선언 파일입니다.
// declare module '모듈 이름' { ... } 구문을 사용합니다.
declare module './StringUtils' {
  /**
   * 주어진 문자열의 첫 글자를 대문자로 변환합니다.
   * @param str 원본 문자열
   * @returns 첫 글자가 대문자로 변환된 문자열
   */
  export function capitalize(str: string): string;

  /**
   * 주어진 문자열이 비어있는지 (null, undefined, 빈 문자열) 확인합니다.
   * @param str 확인할 문자열
   * @returns 비어있으면 true, 아니면 false
   */
  export function isEmpty(str: string | null | undefined): boolean;

  // 만약 기본 내보내기가 있다면 아래와 같이 선언할 수 있습니다.
  // export default class StringUtil { ... }
}

// 참고: 만약 이 js 파일이 ES 모듈처럼 동작한다면, 다음과 같이 직접 export를 선언합니다.
// export function capitalize(str: string): string;
// export function isEmpty(str: string | null | undefined): boolean;

코드 분석

declare module './StringUtils': 이 구문은 특정 모듈에 대한 타입 선언을 시작함을 의미합니다. './StringUtils'는 우리가 타입 정의를 제공하고자 하는 자바스크립트 모듈의 경로(또는 이름)입니다. TypeScript는 이 경로를 사용하여 해당 .js 파일과 이 .d.ts 파일을 연결합니다.

  • 중요: 여기서 모듈 경로는 .js 파일에서 import 또는 require할 때 사용하는 경로와 일치해야 합니다. .js 확장자는 생략하는 것이 일반적입니다.

export function capitalize(str: string): string;: 자바스크립트 파일에서 module.exports.capitalize로 내보냈던 capitalize 함수의 타입 시그니처를 선언합니다. 실제 구현 없이 오직 함수 시그니처만 작성합니다. export 키워드를 사용하여 이 함수가 모듈 외부로 내보내진다는 것을 명시합니다.

export function isEmpty(str: string | null | undefined): boolean;: isEmpty 함수에 대해서도 동일하게 타입 시그니처를 선언합니다. 여기서는 str 매개변수가 string, null, undefined 중 하나일 수 있음을 유니온 타입으로 정확히 명시했습니다.

JSDoc 주석: JSDoc 주석(/** ... */)은 타입스크립트의 타입 정의 파일에서도 유용합니다. IDE나 에디터에서 함수 사용 시 툴팁으로 표시되어 개발자에게 자세한 정보를 제공합니다.


타입 선언 파일 사용하기

이제 app.ts 파일에서 StringUtils 모듈을 가져와 타입 안전하게 사용해봅시다.

타입스크립트 파일 (src/app.ts)

src/app.ts
import { capitalize, isEmpty } from './js/StringUtils'; // .d.ts 파일에 의해 타입 정보가 제공됨

const myString = "hello world";
const capitalizedString = capitalize(myString);
console.log(capitalizedString); // "Hello world"

const emptyString = "";
const isStringEmpty = isEmpty(emptyString);
console.log(`"${emptyString}" is empty: ${isStringEmpty}`); // "is empty: true"

const nullString: string | null = null;
const isNullEmpty = isEmpty(nullString);
console.log(`null is empty: ${isNullEmpty}`); // "is empty: true"

// 잘못된 타입의 인자 전달 시 컴파일 오류 발생
// const num = 123;
// const capitalizedNum = capitalize(num); // Error: 'number' 형식의 인수는 'string' 형식의 매개 변수에 할당될 수 없습니다.

컴파일러 동작

타입스크립트 컴파일러는 import { capitalize, isEmpty } from './js/StringUtils'; 구문을 만나면, 먼저 StringUtils.ts 파일을 찾습니다.

StringUtils.ts 파일이 없으면, StringUtils.d.ts 파일을 찾습니다.

StringUtils.d.ts 파일이 있으면, 해당 파일의 declare module './StringUtils' 블록 안에 정의된 capitalizeisEmpty의 타입 시그니처를 읽어와 app.ts에서 사용되는 이 함수들에 대한 타입 정보를 제공합니다.

이 덕분에 capitalize(myString)와 같이 올바른 타입으로 함수를 호출하면 문제가 없지만, capitalize(num)처럼 잘못된 타입으로 호출하면 컴파일 타임에 오류를 잡아낼 수 있게 됩니다.


전역 타입 선언 (.d.ts 파일의 또 다른 용도)

특정 자바스크립트 코드가 모듈 시스템을 사용하지 않고 전역 스코프에 변수나 함수를 선언하는 경우(예: <script> 태그로 로드되는 레거시 코드나 브라우저 API), declare 키워드를 최상위 레벨에서 사용하여 전역 타입을 선언할 수 있습니다.

전역 타입 선언 파일 (src/types/global.d.ts)

src/types/global.d.ts
// 전역 변수 선언
declare var MY_APP_NAME: string;
declare const VERSION_NUMBER: number;

// 전역 함수 선언
declare function logActivity(message: string, level: 'info' | 'warn' | 'error'): void;

// 전역 인터페이스 확장 (예: Window 객체에 새로운 속성 추가)
interface Window {
  myGlobalData?: {
    userId: number;
    sessionId: string;
  };
}

// 또는 declare namespace를 사용한 전역 객체 선언
declare namespace Analytics {
  function trackEvent(eventName: string, data?: object): void;
  function setUserId(id: string): void;
}

사용 예시 (src/main.ts)

src/main.ts
// 타입스크립트 컴파일러는 global.d.ts를 자동으로 인식합니다.
console.log(`Application Name: ${MY_APP_NAME}`);
console.log(`Version: ${VERSION_NUMBER}`);

logActivity("User logged in", "info");

if (window.myGlobalData) {
  console.log(`User ID: ${window.myGlobalData.userId}`);
}

Analytics.trackEvent("page_view", { path: "/dashboard" });

// logActivity("Invalid level", "debug"); // Error: 'debug' 형식은 '"info" | "warn" | "error"' 형식에 할당될 수 없습니다.

이러한 전역 선언 파일은 tsconfig.jsoninclude 설정에 의해 컴파일러가 인식할 수 있는 경로에 두기만 하면 자동으로 전역 스코프의 타입 정보를 제공합니다.


.d.ts 파일의 배포

직접 작성한 타입스크립트 라이브러리를 npm으로 배포할 때는, tsconfig.jsondeclaration: true 옵션을 사용하여 컴파일 시 .js 파일과 함께 .d.ts 파일을 자동으로 생성하도록 설정합니다.

tsconfig.json
{
  "compilerOptions": {
    "declaration": true,      // .d.ts 파일 자동 생성
    "outDir": "./dist",       // .js 및 .d.ts 파일 출력 디렉토리
    // ...
  }
}

그리고 package.json 파일에 types (또는 typings) 필드를 추가하여, 라이브러리를 사용하는 다른 타입스크립트 프로젝트가 타입 정의 파일을 쉽게 찾을 수 있도록 경로를 명시합니다.

package.json
{
  "name": "my-awesome-library",
  "version": "1.0.0",
  "main": "dist/index.js", // 실제 JS 구현 파일
  "types": "dist/index.d.ts", // 타입 정의 파일
  "files": [
    "dist" // npm publish 시 dist 폴더 포함
  ]
}

이렇게 설정하면, npm install my-awesome-library를 통해 라이브러리를 설치한 사용자들은 자동으로 타입 정보를 받아 타입 안전하게 라이브러리를 사용할 수 있습니다.


.d.ts 파일의 작성과 사용은 타입스크립트가 자바스크립트 생태계와 효과적으로 상호작용하는 핵심적인 방법입니다. 기존 자바스크립트 코드에 타입을 부여하거나, 직접 타입스크립트 라이브러리를 배포할 때 이 .d.ts 파일 작성법을 능숙하게 다루는 것이 중요합니다. declare module, export, 그리고 정확한 타입 시그니처 작성을 통해 코드의 타입 안정성과 개발 경험을 크게 향상시킬 수 있습니다.