.d.ts cheatsheet.

What is a .d.ts

Pure type information — no runtime code. Used to describe:

  • existing JS libraries
  • global ambient types
  • non-code asset imports (CSS, SVG)
  • environment variables

Ambient module

// types/legacy-lib.d.ts
declare module "legacy-lib" {
  export function doThing(s: string): number;
  export const VERSION: string;
}

Now import { doThing } from "legacy-lib" typechecks.

Wildcard ambient module

declare module "*.svg" {
  const content: string;
  export default content;
}

declare module "*.module.css" {
  const classes: { readonly [key: string]: string };
  export default classes;
}

Global declarations

// global.d.ts
declare const VERSION: string;
declare function gtag(...args: any[]): void;

interface Window {
  myApp?: { version: string };
}

Available everywhere without import.

To make a file a module (and isolate declarations), add export {}:

// types/foo.d.ts
export {};

declare global {
  const VERSION: string;
}

Module augmentation

import "express";

declare module "express" {
  interface Request {
    user?: { id: number };
  }
}
import "react";

declare module "react" {
  interface CSSProperties {
    "--my-var"?: string;
  }
}

process.env types

declare global {
  namespace NodeJS {
    interface ProcessEnv {
      DATABASE_URL: string;
      NODE_ENV: "development" | "production" | "test";
      PORT?: string;
    }
  }
}

export {};

Now process.env.DATABASE_URL is string, not string | undefined.

Generating declarations from source

tsconfig.json:

{
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "emitDeclarationOnly": false,
    "outDir": "dist"
  }
}
tsc

Emits .d.ts next to .js.

emitDeclarationOnly + esbuild

{ "emitDeclarationOnly": true, "outDir": "dist" }
tsc                         # types only
esbuild src/index.ts ...    # JS only (faster)

Or use tsup/unbuild to do both.

triple-slash directives

/// <reference types="node" />
/// <reference lib="dom" />
/// <reference path="./other.d.ts" />

Use only in .d.ts. Avoid in source files — prefer tsconfig.json lib/types.

namespace (legacy)

declare namespace Foo {
  export function bar(): void;
  export const baz: string;
}

Foo.bar();

Used in old declaration files. For new code, prefer modules.

Declaration merging

Interfaces with the same name merge:

interface Box { x: number; }
interface Box { y: number; }
// Box now has x and y

Classes + namespace + interface merge in specific patterns:

class Albums { ... }
namespace Albums {
  export const VERSION = "1";
}
Albums.VERSION;

Function with properties

declare function format(s: string): string;
declare namespace format {
  function plural(n: number, s: string): string;
}

format("hi");
format.plural(2, "cats");

Reading existing types

Check node_modules/@types/<pkg> or node_modules/<pkg>/dist/*.d.ts for the published types.

DefinitelyTyped

npm i -D @types/lodash @types/node

Community types for libraries that don’t ship their own.

Stubbing missing types

Quick stub for a no-types library:

declare module "untyped-lib";

Imports as any. Tighten later by writing real types.

skipLibCheck

{ "skipLibCheck": true }

Don’t check types of .d.ts files in node_modules. Saves a lot of time. Recommended.

Publishing types

package.json:

{
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  }
}

Put "types" first in each conditional block — TS picks the first match.

Common mistakes

  • .d.ts with import statements becomes a module — globals stop working without declare global.
  • interface Window { ... } only merges if the file is a module.
  • Triple-slash refs in source files — confusing; use tsconfig.
  • Stale published types — bump after every API change.
  • Mixing namespace and ES modules — pick one.

Read this next

If you want my .d.ts library template, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .