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
// 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:
// 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
# 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
// 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:
index.d.tsin the package (a built-in type)- Statement under
node_modules/@types/ - The locations specified in
tsconfig.json,typeRoots, andtypes
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:
// globals.d.ts
declare var jQuery: (selector: string) => HTMLElement;
declare var $: typeof jQuery;
// Usage
let el = $(".container"); // ✅ Type Safety
(2) Global Function Declarations
// 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:
// 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
// Extend the built-in Array interface
declare module "./types" {
interface Entity {
id: number;
}
}
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:
10
30
// 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:
No runtime output — demonstrates declaration file usage
4. Rules for Writing Declaration Files
(1) Basic Rules
.d.tsThe file contains only declarations; it does not include any implementation.- Use the
declarekeyword to declare an external entity exportis not required—unless it appears in a module declaration- Top-level
exportMakes the file a module declaration (rather than a global declaration)
(2) Three Types of Declaration Scope
// ── 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
// ✅ 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
{
"compilerOptions": {
"typeRoots": [
"./node_modules/@types",
"./src/types"
]
}
}
(2) types—Specify the type packages to include
{
"compilerOptions": {
"types": ["node", "jest", "lodash"]
// Includes only these three @types packages, ignoring the rest
}
}
(3) Three Strictness Options
{
"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:
10
30
// 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:
10
30
▶ Example: Augmenting Built-in Types with Module Declaration
Output:
10
30
// 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:
10
30
❓ FAQ
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.declare module and declare global?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.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..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
- Declaration file
.d.tsprovides type information for JavaScript code—it contains only declarations, no implementation - Three sources of type declarations: TypeScript built-in, library-provided, and @types community packages
- Install third-party type declarations using
npm install @types/package-name - Situations where you write your own declaration files: untyped JavaScript libraries, global variables, and module extensions
declareDeclares an external entity using a keyword;declare moduleDeclares a module type- The
typeRoots/types/noImplicitAny/skipLibChecksetting intsconfigcontrols type resolution and strictness
📝 Exercises
- Basic Problem (Difficulty ⭐): Write a declaration file for a hypothetical
math-helpersJavaScript library that includesadd(a, b),subtract(a, b), and the constantPI. - Advanced Problem (Difficulty ⭐⭐): Write a declaration file that extends the
Stringinterface and adds thereverse(): stringmethod. Think about it: Why does the extension of a built-in type need to be placed in the.d.tsfile? - Challenge (Difficulty: ⭐⭐⭐): Write a complete declaration file for an untyped legacy JavaScript SDK—including a namespace
SDK, a classSDK.Client(constructor + methods), an enumerationSDK.EventType, and a global functionSDK.init(options).