타입스크립트 교재 · 17편 / 20편

namespace 와 .d.ts — 타입만 들어있는 파일

JS 라이브러리에 타입 입히기. @types 의 동작 방식.

고급읽는 시간 7분2026-05-17
.d.ts 파일이 JS 모듈에 타입을 입히는 구조 도식

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>

라이브러리 타입 우선순위

  1. 라이브러리 자체 포함(package.jsontypes/typings 필드) — 최우선.
  2. @types/* 패키지 — node_modules/@types/X 자동 로드.
  3. 프로젝트의 ./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

© 2026 주나이테크(주) @JUNAITECH