[TypeScript] Declaration Files (.d.ts)
정의
Declaration File (.d.ts) 은 타입 정보만 담은 파일입니다. 실행 코드 없이 함수, 클래스, 변수, 모듈의 타입 시그니처 만 선언합니다. JavaScript 라이브러리를 TypeScript 에서 안전하게 사용하기 위한 다리 역할을 합니다.
- 자동 생성:
tsc --declaration시.ts소스에서.d.ts자동 생성 (라이브러리 배포용) - 수동 작성: 순수 JS 라이브러리에 타입 부여
기본 문법
// mylib.d.ts
declare function greet(name: string): string;
declare const VERSION: string;
declare class Client {
constructor(url: string);
send(msg: string): Promise<void>;
}
declare 는 “이것은 런타임에 존재한다고 가정하고 타입만 부여” 를 의미. Emit 안 됨.
Ambient Module
외부 (npm) 모듈 타입 선언:
// mylib.d.ts
declare module "cool-lib" {
export function coolFn(x: number): string;
export const version: string;
export default class Cool {
constructor(opts: {debug?: boolean});
activate(): Promise<void>;
}
}
이후:
import Cool, {coolFn, version} from "cool-lib";
와일드카드 모듈
// assets.d.ts
declare module "*.png" {
const url: string;
export default url;
}
declare module "*.svg" {
import type {ComponentProps, FC} from "react";
const svg: FC<ComponentProps<"svg">>;
export default svg;
}
// 사용
import logo from "./logo.png"; // logo: string
import Icon from "./icon.svg"; // Icon: React component
Ambient Variable
declare const process: {
env: Record<string, string | undefined>;
};
declare const window: Window & {
myGlobal?: string;
};
이런 것들은 lib.dom.d.ts, @types/node 등이 이미 제공.
Global Augmentation
기존 전역 타입 확장:
// global.d.ts
export {}; // 이 파일을 모듈로 표시 (declare global 사용에 필요)
declare global {
interface Window {
myApp: {
version: string;
init(): void;
};
}
interface String {
reverse(): string; // String prototype 확장
}
namespace NodeJS {
interface ProcessEnv {
NEXT_PUBLIC_API_URL: string;
DATABASE_URL: string;
}
}
}
process.env.DATABASE_URL 이 타입 안전. Undefined 없음.
Module Augmentation
기존 npm 모듈 확장:
// express-augment.d.ts
import "express"; // 원본 모듈 로드
declare module "express" {
interface Request {
userId?: string;
auth?: {token: string};
}
}
이제 req.userId, req.auth 를 어디서든 접근 가능. 인증 미들웨어 패턴에 필수.
JSX augmentation (React)
// custom-elements.d.ts
declare namespace JSX {
interface IntrinsicElements {
"my-widget": {color?: string; size?: "sm" | "md" | "lg"};
}
}
// 사용
<my-widget color="red" size="md" />
Web Component 사용 시 유용.
Declaration Merging
같은 이름의 interface / namespace 를 여러 파일에서 선언하면 자동 병합:
// file1.d.ts
interface Config {port: number}
// file2.d.ts
interface Config {host: string}
// = interface Config {port: number; host: string}
Interface merge 만 됨. Type alias 는 안 됨.
Types-only import in .d.ts
Declaration 파일 안에서 타입 가져오기:
// mylib.d.ts
import type {Request, Response} from "express";
declare module "mylib" {
export function middleware(req: Request, res: Response): void;
}
Triple slash directive (legacy)
/// <reference path="./other.d.ts" />
/// <reference types="node" />
지양. import type 이나 tsconfig types 배열로 대체.
DefinitelyTyped
Community 유지 npm 패키지 타입 저장소. @types/* 스코프로 배포.
npm install --save-dev @types/node @types/express @types/react
라이브러리가 자체 타입을 포함하면 @types 불필요. package.json 의 types / typings 필드로 지정.
라이브러리 자체 타입 포함
{
"name": "mylib",
"main": "dist/index.js",
"types": "dist/index.d.ts"
}
tsc --declaration 로 emit 한 .d.ts 를 types 로 노출.
Types 조회 순서
Import 시 TypeScript 는:
- 자체
.d.ts(package.json 의types) @types/{name}패키지- 찾을 수 없음 ->
noImplicitAny상태에 따라 오류 또는any
declaration: true (라이브러리 빌드)
{
"compilerOptions": {
"declaration": true, // .d.ts 생성
"declarationMap": true, // .d.ts.map (IDE go-to-definition)
"emitDeclarationOnly": false, // .js 도 emit
"outDir": "./dist"
}
}
rollup + dts plugin (bundle .d.ts)
큰 라이브러리는 .d.ts 를 하나로 번들:
npm i -D rollup-plugin-dts
// rollup.config.js
import dts from "rollup-plugin-dts";
export default {
input: "./dist/index.d.ts",
output: [{file: "./dist/bundled.d.ts", format: "es"}],
plugins: [dts()],
};
실전: env vars 타입
// env.d.ts
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: "development" | "production" | "test";
DATABASE_URL: string;
SECRET_KEY: string;
PORT?: string;
}
}
process.env.DATABASE_URL 이 string 으로 (undefined 없이). 물론 실제 undefined 방어는 별도.
실전: CSS Modules
// css-modules.d.ts
declare module "*.module.css" {
const classes: {readonly [key: string]: string};
export default classes;
}
declare module "*.module.scss" {
const classes: {readonly [key: string]: string};
export default classes;
}
// 사용
import styles from "./Button.module.css";
<button className={styles.primary}>Click</button>
실전: Vite 환경
// vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_APP_NAME: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
함정
WARNING
declare global 은 module 안에만. 파일이 module (import / export 포함) 이어야 함. 상단에 export {}; 트릭.
CAUTION
Ambient 는 컴파일 시만. 실제 런타임에 그 module 이 없으면 오류. 파일 매핑 (webpack, vite alias) 필요.
WARNING
@types 버전 불일치. 라이브러리 버전과 다른 @types 버전이면 타입 오류. npm-check-updates 로 동기화.
IMPORTANT
자체 타입 포함 시 @types 무시하도록. package.json 의 types 필드가 최우선.
CAUTION
JSDoc 도 있음. .d.ts 대신 JSDoc 으로 타입 부여 가능 (@type, @param). 순수 JS 라이브러리 문서화에 활용.
관련 위키
- TypeScript - 상위 개요
- Modules - Module resolution
- Strict Mode - noImplicitAny
- Interfaces - Declaration merging
- Generics - Generic .d.ts
- ES Modules
이 글의 용어 (6개)
- [Javascript] ES Modules (import / export)javascript
- 정의 ES Modules (ESM) 은 표준 JS 모듈 시스템 (ES6). / 키워드. 브라우저와 Node.js 16+ 모두 지원. export named export defau…
- [TypeScript] Genericstypescript
- 정의 Generics 는 타입을 파라미터화하는 문법입니다. 함수, 클래스, 인터페이스, type alias 가 재사용 가능 하면서도 타입 안전 하도록 만듭니다. Java 의 ge…
- [TypeScript] Interfacestypescript
- 정의 Interface 는 객체의 shape (형태) 을 정의하는 TypeScript 문법입니다. 필드, 메서드, 인덱스 시그니처, 호출 시그니처를 선언하며, 로 상속하고 dec…
- [TypeScript] Modules (import/export, moduleResolution)typescript
- 정의 TypeScript 모듈 시스템은 ES Modules (ESM) 를 기본 언어 모델로 삼되, CommonJS (CJS) 를 상호운용성 (interop) 계층으로 지원합니다.…
- [TypeScript] Strict Mode & tsconfigtypescript
- 정의 Strict Mode 는 여러 엄격한 타입 검사 플래그를 한 번에 켜는 옵션 ( ) 입니다. 강력한 타입 안전성을 제공하지만, 기존 코드베이스에는 대량의 오류를 발생시킬 수…
- TypeScripttypescript
- 정의 TypeScript 는 Microsoft 가 2012년 발표한 JavaScript 의 상위 집합 프로그래밍 언어입니다. 정적 타입 시스템, 인터페이스, 제네릭, enum, …
💬 댓글