namespace 와 .d.ts — 타입만 들어있는 파일
JS 라이브러리에 타입 입히기. @types 의 동작 방식.
JS 만 있는 라이브러리에 어떻게 타입을 입히나? 또는 글로벌 객체에 새 속성을 추가하려면? 답은 .d.ts(declaration 파일) — 런타임 코드 없이 타입 선언만 담은 파일. 17편은 namespace 의 현재 위상, .d.ts 의 모양, 그리고 거의 모든 라이브러리가 의지하는 @types/*(DefinitelyTyped) 까지.
.d.ts 파일이란 — 런타임 코드 0
// math.d.ts — 타입 "선언" 만 있음 (구현 없음)
export declare function add(a: number, b: number): number;
export declare const PI: number;
export interface Point {
x: number;
y: number;
}
// 별도 math.js 가 진짜 구현
function add(a, b) { return a + b; }
const PI = 3.14159;
module.exports = { add, PI };
.d.ts 의 핵심: JS 코드는 실행되고, TS 컴파일러는 .d.ts 를 보고 타입 추론. 옛 JS 라이브러리가 TS 와 어울리는 방법.
declare 키워드 — "이미 있다고 가정"
// 외부에서 주입되는 글로벌 (script 태그로 로드되는 라이브러리 등)
declare const $: (selector: string) => HTMLElement[]; // jQuery 같은
declare function gtag(command: string, ...args: any[]): void; // GA
// 사용
$("button").forEach(b => b.click());
gtag("event", "click");
// declare 가 없으면 "Cannot find name '$'" 에러
declare module — 외부 모듈 타입 입히기
// types/old-lib.d.ts
declare module "old-lib" {
export function doStuff(x: string): number;
export const version: string;
export default function (config: { url: string }): Promise<void>;
}
// 사용 — 일반 import 처럼
import oldLib, { doStuff, version } from "old-lib";
doStuff("hi"); // 타입 추론 OK
declare global — 글로벌 확장
// types/global.d.ts
declare global {
interface Window {
myApp: {
version: string;
log(msg: string): void;
};
}
// env 타입 — Node
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
API_KEY: string;
}
}
}
export {}; // 모듈로 인식되게 (글로벌 declare 한정자 동작)
// 사용
window.myApp.log("hi"); // OK
process.env.DATABASE_URL; // OK, 타입 보장
declare global 의 함정. 글로벌을 변경하면 같은 프로젝트의 모든 코드에 영향. 필요 최소한만, 그리고 한 파일에 모아두기. 라이브러리(특히 React-Three-Fiber·Express 등) 의 타입 확장 패턴으로 많이 쓰입니다.
declaration merging — interface 의 특기 (4편 다시)
// types/express.d.ts — Express Request 에 user 필드 추가
import { User } from "../models/user";
declare global {
namespace Express {
interface Request {
user?: User;
}
}
}
export {};
// app.ts
import express from "express";
const app = express();
app.use((req, res, next) => {
req.user = await loadUser(req.headers.auth); // 타입 OK
next();
});
@types/* — DefinitelyTyped
# 옛 라이브러리 (TS 안 쓰는) → 별도 타입 패키지
npm install lodash
npm install -D @types/lodash
# react·node 등 큰 라이브러리도 마찬가지
npm install -D @types/react @types/node
# package.json
{
"devDependencies": {
"@types/lodash": "^4.17.0",
"@types/node": "^22.0.0"
}
}
DefinitelyTyped 는 커뮤니티가 유지하는 거대한 타입 저장소. npm install @types/X 로 설치하면 TS 가 자동으로 인식. 현대 라이브러리는 보통 자체 .d.ts 를 포함해 @types 가 필요 없음.
tsconfig — typeRoots · types
{
"compilerOptions": {
// 기본값: node_modules/@types 의 모든 패키지 자동 로드
"typeRoots": ["./node_modules/@types", "./types"],
// 특정 것만 로드 (자동 로드 끔)
"types": ["node", "vite/client"],
// skipLibCheck — node_modules 의 .d.ts 검사 생략 (속도)
"skipLibCheck": true
}
}
namespace — 현재 위상
// 옛 TS 의 모듈 시스템 (ES 모듈 이전)
namespace MyLib {
export function add(a: number, b: number): number {
return a + b;
}
export namespace Math {
export const PI = 3.14;
}
}
MyLib.add(1, 2);
MyLib.Math.PI;
namespace 의 운명. ES 모듈 표준(import/export) 이 등장하면서 거의 사용하지 않습니다. 새 코드는 ES 모듈 한 가지. namespace 가 여전히 쓰이는 곳: ① 글로벌 타입 그룹화(namespace Express { ... }), ② 옛 라이브러리 .d.ts. 새 모듈은 만들지 마세요.
실전 — vite·webpack 의 모듈 핸들링 타입
// types/assets.d.ts — 이미지 import 타입
declare module "*.png" {
const src: string;
export default src;
}
declare module "*.svg" {
const src: string;
export default src;
}
declare module "*.css" {
const classes: Record<string, string>;
export default classes;
}
// 사용
import logo from "./logo.png"; // logo: string (URL)
import styles from "./app.css"; // styles: Record<string, string>
라이브러리 타입 우선순위
- 라이브러리 자체 포함(
package.json의types/typings필드) — 최우선. - @types/* 패키지 — node_modules/@types/X 자동 로드.
- 프로젝트의 ./types/*.d.ts — 직접 작성.
한 줄 가이드
- 현대 라이브러리 — 그냥
npm install, 타입은 자동. - 옛 라이브러리 —
npm install -D @types/X. 없으면 자체 .d.ts 작성. - 글로벌 객체 확장 —
declare global+export {}. - 이미지·CSS 같은 자산 import — 한 번에
declare module "*.png". - namespace 는 새로 만들지 말 것 — declaration merging 한정.
18편 — strict 모드 깊이
strict 가족 옵션들과 noUncheckedIndexedAccess·exactOptionalPropertyTypes 실전.
이전: 16편 데코레이터 · 현재: 17편 (고급) · 다음 → 18편 strict 깊이 · 진행: 17/20