⚡IntermediateModules & Declaration Files

Declaration Files & @types

Understand how .d.ts files work, when to write your own, and how DefinitelyTyped and @types packages bring type safety to the JavaScript ecosystem.

Overview

TypeScript can only type-check code it knows about. For JavaScript libraries without built-in types, TypeScript uses **declaration files** (`.d.ts`) - pure type information files that describe the shapes of modules without any runtime code. **DefinitelyTyped** is the community repository that provides `@types/` packages for thousands of JavaScript libraries. When you install `@types/lodash`, you get a `.d.ts` file that tells TypeScript exactly what `lodash` exports and what types each function expects and returns. You write your own declaration files when: - You have local JavaScript files in a TypeScript project - You are publishing a library and want to ship types with it - A `@types/` package doesn't exist for a library you're using Declaration files use the same type syntax as TypeScript but contain only `declare` statements - no implementations.

Key Points

  • •Declaration files end in `.d.ts` and contain only type information - no runtime code
  • •`declare module "name"` defines the shape of an external module
  • •`declare global` extends the global scope with new types
  • •`@types/` packages (from DefinitelyTyped) are installed with `npm install --save-dev @types/library-name`
  • •TypeScript finds `@types/` packages automatically; no import needed for global types
  • •`"types"` field in package.json tells TypeScript where a library's declaration file lives
  • •`"skipLibCheck": true` in tsconfig skips type checking `.d.ts` files (speeds up builds)
  • •Ambient declarations: `declare const`, `declare function`, `declare class` - describe globals

Examples

Writing a basic declaration file for a JS library

// Say you have a JS file: utils.js
// export function formatDate(date, format) { ... }
// export function clamp(value, min, max) { ... }

// You create utils.d.ts to describe its types:

declare module './utils' {
  export function formatDate(date: Date, format: string): string;
  export function clamp(value: number, min: number, max: number): number;
}

// Or if it's a global module (no import needed):
declare function formatDate(date: Date, format: string): string;
declare const APP_VERSION: string;

// Now TypeScript understands the types:
import { formatDate, clamp } from './utils';

const formatted = formatDate(new Date(), 'YYYY-MM-DD'); // string
const clamped   = clamp(150, 0, 100);                   // number

Using @types packages

// Install: npm install --save-dev @types/lodash
// TypeScript now knows lodash's types

import _ from 'lodash';

// Full type safety  -  IntelliSense knows all lodash methods
const users = [
  { name: 'Alice', age: 30 },
  { name: 'Bob',   age: 25 },
  { name: 'Carol', age: 35 },
];

const sorted = _.sortBy(users, 'age');
// sorted: { name: string; age: number }[]

const byName = _.keyBy(users, 'name');
// byName: { [key: string]: { name: string; age: number } }

const chunked = _.chunk([1, 2, 3, 4, 5], 2);
// chunked: number[][]

// Without @types/lodash, all of these would be 'any'

Ambient module declarations and global augmentation

// Declare a module for file types TypeScript doesn't understand
// (e.g., in a bundler that handles .svg imports)
// src/global.d.ts

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

declare module '*.png' {
  const content: string;
  export default content;
}

// Extend globalThis with your own globals
declare global {
  interface Window {
    analytics: {
      track: (event: string, data?: Record<string, unknown>) => void;
    };
  }

  const __DEV__: boolean;
  const __VERSION__: string;
}

// Now these work without errors:
window.analytics.track('page_view', { path: '/home' });

if (__DEV__) {
  console.log('Development mode:', __VERSION__);
}

Common Mistakes

  • Installing `@types/package` for a library that already ships its own types (like `axios` or `zod`) - this causes type conflicts; check if the package has a `"types"` field in its package.json first
  • Writing `.d.ts` files with implementation code - declaration files must only contain `declare` statements; any actual code goes in `.ts` files
  • Forgetting that `declare global` must be inside a module (a file with at least one import/export) - otherwise TypeScript treats the whole file as a global script and `declare global` is redundant

Note

Before writing a `.d.ts` file for a popular library, check `https://www.npmjs.com/package/@types/library-name` or look for a `"types"` field in the library's `package.json`. Most popular packages already have types. Only write your own declarations for internal JS files, niche libraries, or file-type imports (like `.svg`, `.css`).

Exercises

Write TypeScript code to solve each exercise. Click Run to compile and execute it right here, then mark as done.

Loading editor…

Completed: 0 / 3 exercises

Knowledge Check

Question 1 of 4

What is the purpose of a `.d.ts` file?