advanced Step 13 of 18

Declaration Files

TypeScript Programming

Declaration Files (.d.ts)

Declaration files are TypeScript files with a .d.ts extension that contain only type declarations — no executable code. They describe the shape of JavaScript libraries so that TypeScript can type-check your code even when using libraries written in plain JavaScript. The DefinitelyTyped repository on GitHub hosts community-maintained declaration files for thousands of popular npm packages, installable as @types/packagename. Understanding how to consume, author, and troubleshoot declaration files is a critical skill for working in mixed JavaScript and TypeScript codebases.

Using @types Packages

Many popular JavaScript libraries do not ship with built-in TypeScript types. The DefinitelyTyped project fills this gap by providing declaration files packaged under the @types scope on npm.

# Install type declarations for common libraries
npm install --save-dev @types/node
npm install --save-dev @types/express
npm install --save-dev @types/lodash
npm install --save-dev @types/jest

# TypeScript automatically picks up @types packages.
# You can now import with full type safety:
import express from "express";
import _ from "lodash";

const app = express();

app.get("/users", (req, res) => {
  // req and res are fully typed thanks to @types/express
  const name = req.query.name; // type: string | ParsedQs | ...
  res.json({ name });
});

const numbers = [3, 1, 4, 1, 5, 9];
const sorted = _.sortBy(numbers); // fully typed as number[]

Writing Declaration Files

When a library has no @types package, you can write your own declaration file. Declaration files use the declare keyword to describe types without providing implementations.

// types/analytics.d.ts
// Declare a module for a JavaScript analytics library
declare module "analytics-lib" {
  interface EventProperties {
    [key: string]: string | number | boolean;
  }

  interface AnalyticsConfig {
    apiKey: string;
    debug?: boolean;
    batchSize?: number;
  }

  export function init(config: AnalyticsConfig): void;
  export function track(event: string, properties?: EventProperties): void;
  export function identify(userId: string, traits?: Record<string, unknown>): void;
  export function page(name: string): void;
}
// Now you can use the library with full types
import { init, track, identify } from "analytics-lib";

init({ apiKey: "abc123", debug: true });
track("button_click", { label: "signup", page: "home" });
identify("user-42", { plan: "premium" });

Ambient Declarations

Ambient declarations describe global variables, functions, or objects that exist at runtime but are not imported via modules. This is common for browser globals, environment variables, and scripts loaded via CDN.

// types/globals.d.ts
// Declare a global variable injected by a script tag
declare const API_BASE_URL: string;
declare const APP_VERSION: string;

// Declare a global function
declare function gtag(command: string, ...args: unknown[]): void;

// Extend the Window interface
interface Window {
  analytics: {
    track(event: string): void;
    page(name: string): void;
  };
}

// Declare environment variable types for Vite
interface ImportMetaEnv {
  readonly VITE_API_URL: string;
  readonly VITE_APP_TITLE: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

Generating Declaration Files

When you build a TypeScript library that will be consumed by others, you should generate declaration files alongside the compiled JavaScript. Enable the declaration option in tsconfig.json.

{
  "compilerOptions": {
    "declaration": true,
    "declarationDir": "./dist/types",
    "emitDeclarationOnly": false,
    "outDir": "./dist"
  }
}

// package.json — point consumers to your types
{
  "main": "./dist/index.js",
  "types": "./dist/types/index.d.ts"
}

Triple-Slash Directives

Triple-slash directives are special comments that reference other declaration files or type packages. They are used mainly in declaration files themselves and in scripts that are not modules.

/// <reference types="node" />
/// <reference path="./custom-types.d.ts" />

// These directives tell the compiler to include the
// referenced types when processing this file.
Tip: Before writing custom declaration files, check if @types/packagename already exists. Run npm search @types/packagename or browse the DefinitelyTyped repository. Writing declaration files from scratch is only necessary for internal or obscure libraries.

Key Takeaways

  • Declaration files (.d.ts) contain type-only descriptions of JavaScript code.
  • Install community-maintained types from DefinitelyTyped with npm install @types/package.
  • Use declare module to write custom type definitions for untyped libraries.
  • Ambient declarations describe global variables and functions available at runtime.
  • Enable "declaration": true in tsconfig.json to generate .d.ts files for your own libraries.