TypeScript by Example

Declaration Files

Writing .d.ts files for untyped JavaScript modules, globals, @types packages, and augmentation.

A declaration file (.d.ts) describes JavaScript to TypeScript without containing runtime code. It is type information only.

Use declare module when a JavaScript package has no bundled types and no @types package.

// types/untyped-logger.d.ts
declare module "untyped-logger" {
  export interface Logger {
    info(msg: string, meta?: Record<string, unknown>): void;
    error(msg: string, error?: Error): void;
  }
 
  export function createLogger(name: string): Logger;
}
// app.ts
import { createLogger } from "untyped-logger";
 
const log = createLogger("api");
log.info("server started", { port: 3000 });

Global augmentation extends existing global or framework types. Put it in a module-shaped declaration file. @types/ packages provide declarations for many untyped npm libraries.

// types/express-user.d.ts
import "express";
 
declare global {
  namespace Express {
    interface Request {
      user?: { id: string; role: "admin" | "member" };
    }
  }
}
// app.ts, with @types/node installed
const buf = Buffer.from("hello");

In production

Pin runtime packages and matching @types/ versions together. A major-version mismatch can break typechecking even when runtime behavior has not changed.

Enjoyed this? Get more software craft delivered to your inbox.