TypeScript: TypeScript Declaration Files

Last updated: 2026-08-26

Declaration files (.d.ts) serve as a bridge between the TypeScript and JavaScript worlds—they provide type definitions for JavaScript code that lacks type information, allowing you to safely use any JavaScript library in your TypeScript projects.

1. What Is a Declaration File?

(1) Issue: JS library lacks types

TYPESCRIPT
// Usage lodash —— A pure JavaScript library
import _ from "lodash";

// ❌ TypeScript Error: Module not found "lodash" Statement Document
let result = _.chunk([1, 2, 3, 4], 2);

(2) Solution: The declaration file provides type information

Declaration files have the suffix .d.ts and contain only type declarations; they do not include implementation code:

TYPESCRIPT
// lodash.d.ts —— Statement(Describe only the type,No implementation provided)
declare module "lodash" {
  export function chunk<T>(array: T[], size: number): T[][];
  export function debounce(func: Function, wait: number): Function;
  // ... Additional Statements
}

With the declaration file, TypeScript can understand the lodash API and provide type checking and code hints.

(3) Three Sources of Declaration Documents

Source Description Example
Built-in declarations Included in TypeScript (DOM, ES2020, etc.) lib.dom.d.ts
Included in the package The library author has included .d.ts axios/index.d.ts
DefinitelyTyped Community-maintained third-party declarations @types/lodash


2. Installing and Using the @types Package

(1) Look up type declarations

BASH
# Check if a package has @types Statement
npm info @types/lodash

# Installation Type Declaration
npm install @types/lodash --save-dev

(2) The result after installation

TYPESCRIPT
// After installing @types/lodash — full type support
import _ from "lodash";

let chunks: number[][] = _.chunk([1, 2, 3, 4], 2);  // ✅ Type Safety
let debounced = _.debounce(() => {}, 300);            // ✅ Auto-Complete

(3) Common @types packages

Package Name Corresponding Library
@types/node Node.js
@types/lodash Lodash
@types/jest Jest
@types/react React
@types/jquery jQuery

(4) Automatic Discovery of Type Declarations

TypeScript looks for type declarations in the following order:

  1. index.d.ts in the package (a built-in type)
  2. Statement under node_modules/@types/
  3. The locations specified in tsconfig.json, typeRoots, and types


3. Write Your Own Declaration File

(1) Declaring Global Variables

When importing a JavaScript library using the script tag, you need to declare global variables:

TYPESCRIPT
// globals.d.ts
declare var jQuery: (selector: string) => HTMLElement;
declare var $: typeof jQuery;

// Usage
let el = $(".container");  // ✅ Type Safety

(2) Global Function Declarations

TYPESCRIPT
// globals.d.ts
declare function ga(command: string, ...args: any[]): void;
declare function gtag(type: string, eventName: string, params?: Record<string, any>): void;

// Usage
ga("send", "pageview");               // ✅
gtag("event", "click", { value: 1 });  // ✅

(3) Module Declaration

When using untyped npm packages, declare the module as follows:

TYPESCRIPT
// declarations.d.ts
declare module "untyped-lib" {
  export function doSomething(value: string): number;
  export const version: string;
  export default class Client {
    constructor(options: { host: string; port: number });
    connect(): Promise<void>;
  }
}

// Usage
import Client, { doSomething, version } from "untyped-lib";

(4) Module Extensions—Adding Types to Built-in Modules

TYPESCRIPT
// Extend the built-in Array interface
declare module "./types" {
  interface Entity {
    id: number;
  }
}
💡 Tip: Module augmentation uses declare module to extend existing type definitions. This is the same technique used by @types packages to add properties to global types like Window or Array.

▶ Example: Writing a declaration for a custom JavaScript tool

Output:

TEXT 📖 Display only
10
30
TYPESCRIPT
// Suppose there is a legacy-utils.js The file has no type
// legacy-utils.d.ts —— Write a statement for it

declare module "legacy-utils" {
  /**
   * Format the date according to the specified pattern
   * @param date - Date object or timestamp
   * @param pattern - Format patterns, e.g. "YYYY-MM-DD"
   */
  export function formatDate(date: Date | number, pattern: string): string;

  /**
   * Deep-copy objects
   */
  export function deepClone<T>(obj: T): T;

  /**
   * Image Stabilization Function
   */
  export function debounce<T extends (...args: any[]) => any>(
    fn: T,
    delay: number
  ): (...args: Parameters<T>) => void;

  /**
   * Default Export:Toolset Object
   */
  const utils: {
    formatDate: typeof formatDate;
    deepClone: typeof deepClone;
    debounce: typeof debounce;
  };

  export default utils;
}

// Usage——Full Type Support
import utils from "legacy-utils";

let dateStr = utils.formatDate(new Date(), "YYYY-MM-DD");
let cloned = utils.deepClone({ name: "Charlie" });
let debounced = utils.debounce((x: number) => console.log(x), 300);

Output:

TEXT 📖 Display only
No runtime output — demonstrates declaration file usage


4. Rules for Writing Declaration Files

(1) Basic Rules

(2) Three Types of Declaration Scope

TYPESCRIPT
// ── Global Declarations(None import/export) ──
// All declarations in the file are automatically visible throughout the entire project.
declare var GLOBAL_CONFIG: { api: string };
declare function globalHelper(): void;

// ── Module Declaration ──
declare module "my-lib" {
  export function helper(): void;
}

// ── File Module Declaration ──
// At the top of the document, there is import/export → The entire file is a module
import { User } from "./types";
export declare function processUser(user: User): void;

(3) Guidelines for Type Export

TYPESCRIPT
// ✅ Recommendations——Export Interfaces and Types
export interface User {
  id: number;
  name: string;
}

export type UserId = number;

// ✅ Recommendations——Exported Function Signatures
export declare function getUser(id: number): User;

// ❌ Not recommended——Export the specific implementation(.d.ts Should not be implemented)
// export function getUser(id: number): User { return ...; }


5. Type Configuration in tsconfig

(1) typeRoots—Specifies the directory for type declarations

JSON
{
  "compilerOptions": {
    "typeRoots": [
      "./node_modules/@types",
      "./src/types"
    ]
  }
}

(2) types—Specify the type packages to include

JSON
{
  "compilerOptions": {
    "types": ["node", "jest", "lodash"]
    // Includes only these three @types packages, ignoring the rest
  }
}

(3) Three Strictness Options

JSON
{
  "compilerOptions": {
    "noImplicitAny": true,          // Implicit is prohibited any
    "strict": true,                  // Enable all strict checks
    "skipLibCheck": true             // Skip .d.ts File Type Validation(Speed up compilation)
  }
}

▶ Example: Declaring Global Types in a .d.ts File

Output:

TEXT 📖 Display only
10
30
TYPESCRIPT
// env.d.ts — declare global constants and types
declare var APP_VERSION: string;
declare var API_BASE_URL: string;

interface AppWindow extends Window {
  appConfig: {
    theme: "light" | "dark";
    locale: string;
  };
}

// Usage in any .ts file
console.log(`v${APP_VERSION}`);
console.log(APP_VERSION);

Output:

TEXT 📖 Display only
10
30

▶ Example: Augmenting Built-in Types with Module Declaration

Output:

TEXT 📖 Display only
10
30
TYPESCRIPT
// array-ext.d.ts — add a method to the built-in Array type
interface Array<T> {
  last(): T | undefined;
  first(): T | undefined;
}

// Now every array has .last() and .first() with full type safety
let items = [10, 20, 30];
let first = items.first();   // number | undefined
let last = items.last();     // number | undefined

console.log(first);  // 10
console.log(last);   // 30

Output:

TEXT 📖 Display only
10
30

❓ FAQ

Q When do you need to write a declaration file?
A There are three scenarios: (1) The JavaScript library you're using doesn't have an @types package; (2) Global variables imported via a script tag; (3) You need to add custom properties to an existing module. In most cases, installing @types is sufficient; writing your own declaration file is a relatively rare practice.
Q What is the difference between declare module and declare global?
A declare module "xxx" Declares the type of an external module—used to provide types for npm packages. declare global Adds a declaration to the global namespace within a module file—used to extend global types (such as Window). The two have different scopes: module is module-level, while global is global-level.
Q Which takes precedence—the @types package or the library’s built-in types?
A The library’s built-in types take precedence. Modern libraries (such as axios and zod) already include index.d.ts within the package, so there’s no need to install @types separately. You only need @types when the library doesn’t include its own types. If both are present, TypeScript will prioritize the declarations included in the package.
Q Should skipLibCheck be enabled?
A We recommend enabling it. skipLibCheck skips type checking for all .d.ts files, which can significantly speed up compilation (especially for large projects). The downside is that it may miss errors in third-party type declarations—but this risk is minimal because the @types package is reviewed by the community. The performance benefits far outweigh the risks.

📖 Summary

📝 Exercises

  1. Basic Problem (Difficulty ⭐): Write a declaration file for a hypothetical math-helpers JavaScript library that includes add(a, b), subtract(a, b), and the constant PI.
  2. Advanced Problem (Difficulty ⭐⭐): Write a declaration file that extends the String interface and adds the reverse(): string method. Think about it: Why does the extension of a built-in type need to be placed in the .d.ts file?
  3. Challenge (Difficulty: ⭐⭐⭐): Write a complete declaration file for an untyped legacy JavaScript SDK—including a namespace SDK, a class SDK.Client (constructor + methods), an enumeration SDK.EventType, and a global function SDK.init(options).
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏