Introduction
Declaration files (.d.ts) describe the shape of JavaScript code without containing any implementation. They are the bridge between TypeScript's type system and the vast ecosystem of untyped JavaScript libraries. Understanding how they work is essential for consuming third-party packages and publishing your own typed libraries.
Key Concepts
- Declaration File (.d.ts): A file containing only type information — no runtime code. It tells TypeScript what types a JavaScript module exports.
- Ambient Declaration: A
declarestatement that tells TypeScript about values that exist at runtime but are not defined in the current file. - DefinitelyTyped (@types): A community repository of declaration files for popular JavaScript libraries.
Real World Context
When you import lodash in a TypeScript project, TypeScript needs to know what functions lodash exports and what types they accept. If lodash does not ship its own types, you install @types/lodash from DefinitelyTyped. These @types packages contain .d.ts files that describe lodash's API.
Deep Dive
How TypeScript Finds Declarations
When you write import _ from "lodash", TypeScript looks for types in this order:
lodash/index.d.ts(bundled with the package)@types/lodash/index.d.ts(from DefinitelyTyped)- A
pathsmapping in your tsconfig
Generating Declaration Files
Enable declaration in tsconfig to generate .d.ts files from your source:
json{ "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": false, "outDir": "./dist" } }
For a source file src/utils.ts:
typescriptexport function add(a: number, b: number): number { return a + b; }
TypeScript generates dist/utils.d.ts:
typescriptexport declare function add(a: number, b: number): number;
Ambient Declarations
Use declare for values injected by the runtime environment:
typescript// globals.d.ts declare const __APP_VERSION__: string; declare const __DEV__: boolean; // Usage in any .ts file console.log(`Version: ${__APP_VERSION__}`); if (__DEV__) { enableDebugMode(); }
Triple-Slash Directives
Reference additional type files:
typescript/// <reference types="node" /> /// <reference path="./custom-types.d.ts" />
Common Pitfalls
- Forgetting declarationMap — Without
.d.ts.mapfiles, "Go to Definition" in your IDE jumps to the.d.tsfile instead of the source.tsfile. Always enabledeclarationMap. - Conflicting ambient declarations — Two
.d.tsfiles declaring the same global can cause errors. Use module-scoped declarations when possible.
Best Practices
- Enable declaration + declarationMap for libraries — Consumers get types and can navigate to source code.
- Use @types only as a fallback — Prefer packages that bundle their own types. Bundled types are always version-matched.
Summary
- Declaration files (
.d.ts) provide type information for JavaScript code. - TypeScript generates them automatically with
declaration: true. declarecreates ambient declarations for runtime globals.- DefinitelyTyped (
@types) provides types for packages that don't bundle their own.
Code Examples
// globals.d.ts — declare runtime globals
declare const __APP_VERSION__: string;
declare const __BUILD_TIME__: number;
// env.d.ts — type environment variables
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: "development" | "production" | "test";
DATABASE_URL: string;
API_KEY?: string;
}
}
// Usage — TypeScript knows these exist
console.log(__APP_VERSION__);
console.log(process.env.DATABASE_URL); // string, not string | undefined