Imagine that in Jurassic Park, ancient artifacts were discovered - mysterious tablets with descriptions of dinosaur species, written in an unknown language. Scientists had to create "translation dictionaries" to understand what those tablets described. In the TypeScript world, declaration files (.d.ts) serve the role of such dictionaries - they describe the shape of JavaScript code that itself has no type information.
Declaration files are files with the
.d.ts extension that contain only type information - without implementation. They serve to describe the shape of JavaScript libraries, external modules, and global objects.1// file: dinosaur-tracker.d.ts
2// Describing an external JavaScript library
3
4declare module 'dinosaur-tracker' {
5 export interface DinosaurPosition {
6 id: string;
7 species: string;
8 latitude: number;
9 longitude: number;
10 lastSeen: Date;
11 }
12
13 export function trackDinosaur(id: string): DinosaurPosition;
14 export function getAllPositions(): DinosaurPosition[];
15 export function setAlert(species: string, radius: number): void;
16}Thanks to this file, TypeScript knows what functions and types the
dinosaur-tracker module exports, even though the module itself is written in plain JavaScript.The
declare keyword tells TypeScript: "this element exists at runtime, but you don't need to compile it - just trust me." We use it to describe:1// Global variable available in the browser
2declare const PARK_CONFIG: {
3 name: string;
4 maxCapacity: number;
5 securityLevel: 'low' | 'medium' | 'high' | 'critical';
6};
7
8// Now we can use it with full type safety
9console.log(PARK_CONFIG.name);
10console.log(PARK_CONFIG.securityLevel);
11// PARK_CONFIG.unknownField; // Compilation error!1// Function defined in an external script
2declare function initializeFence(
3 zone: string,
4 voltage: number
5): { active: boolean; zone: string };
6
7declare function emergencyShutdown(): void;
8
9// Usage with type safety
10const fence = initializeFence('raptor-paddock', 10000);
11console.log(fence.active); // OK
12// console.log(fence.power); // Error! No such property1declare class SecuritySystem {
2 constructor(zones: string[]);
3 arm(zone: string): void;
4 disarm(zone: string): void;
5 getStatus(): Record<string, boolean>;
6}
7
8declare namespace ParkAPI {
9 interface Visitor {
10 id: string;
11 name: string;
12 ticket: 'standard' | 'vip' | 'researcher';
13 }
14
15 function registerVisitor(name: string, ticket: Visitor['ticket']): Visitor;
16 function getVisitorCount(): number;
17}
18
19// Usage
20const system = new SecuritySystem(['zone-a', 'zone-b']);
21system.arm('zone-a');
22
23const visitor = ParkAPI.registerVisitor('Alan Grant', 'researcher');
24console.log(visitor.ticket);When you use a JavaScript library that doesn't have types, you need to write your own
.d.ts file:1// file: types/legacy-dino-db.d.ts
2// Describing an old JS library for managing a dinosaur database
3
4declare module 'legacy-dino-db' {
5 export interface DinosaurRecord {
6 id: string;
7 species: string;
8 diet: 'herbivore' | 'carnivore' | 'omnivore';
9 weight: number;
10 height: number;
11 dangerLevel: 1 | 2 | 3 | 4 | 5;
12 }
13
14 export interface QueryOptions {
15 limit?: number;
16 offset?: number;
17 sortBy?: keyof DinosaurRecord;
18 order?: 'asc' | 'desc';
19 }
20
21 export class DinoDB {
22 constructor(connectionString: string);
23 connect(): Promise<void>;
24 disconnect(): Promise<void>;
25 findAll(options?: QueryOptions): Promise<DinosaurRecord[]>;
26 findById(id: string): Promise<DinosaurRecord | null>;
27 insert(record: Omit<DinosaurRecord, 'id'>): Promise<DinosaurRecord>;
28 update(id: string, data: Partial<DinosaurRecord>): Promise<DinosaurRecord>;
29 delete(id: string): Promise<boolean>;
30 }
31
32 // Default export
33 export default DinoDB;
34}DefinitelyTyped is a huge repository on GitHub containing declaration files for thousands of JavaScript libraries. Instead of writing your own
.d.ts files, you can install ready-made types:1// Installing types for popular libraries:
2// npm install --save-dev @types/express
3// npm install --save-dev @types/lodash
4// npm install --save-dev @types/node
5
6// After installing @types/express you can write:
7import express, { Request, Response, NextFunction } from 'express';
8
9const app = express();
10
11// TypeScript knows the types Request, Response, NextFunction
12app.get('/dinosaurs/:id', (req: Request, res: Response) => {
13 const dinoId: string = req.params.id;
14 res.json({ id: dinoId, species: 'T-Rex' });
15});
16
17// Without @types/express - no type information!
18// req, res would be of type "any"TypeScript searches for types in the following order:
1// 1. Types built into the package ("types" field in package.json)
2// Many modern libraries have built-in .d.ts
3// e.g. axios, zod, prisma
4
5// 2. @types packages from node_modules/@types/
6// Automatically recognized by TypeScript
7// e.g. @types/react, @types/node
8
9// 3. Custom .d.ts files in the project
10// Configuration in tsconfig.json:
11// {
12// "compilerOptions": {
13// "typeRoots": ["./node_modules/@types", "./types"],
14// "types": ["node", "express"]
15// },
16// "include": ["src/**/*", "types/**/*"]
17// }
18
19// 4. Triple-slash directives (rarely used)
20/// <reference types="node" />
21/// <reference path="./custom-types.d.ts" />Sometimes you need to declare a module that is not an npm package - for example, a CSS file, an image, or a JSON file:
1// file: types/assets.d.ts
2
3// Importing CSS files
4declare module '*.css' {
5 const classes: Record<string, string>;
6 export default classes;
7}
8
9// Importing image files
10declare module '*.png' {
11 const src: string;
12 export default src;
13}
14
15declare module '*.svg' {
16 const content: string;
17 export default content;
18}
19
20// Importing JSON files
21declare module '*.json' {
22 const value: Record<string, unknown>;
23 export default value;
24}
25
26// Now you can import these files with type safety:
27// import styles from './styles.css';
28// import logo from './logo.png';
29// import dinoData from './dinosaurs.json';.d.ts files allow extending types from external libraries:1// file: types/express-extension.d.ts
2// Extending Express types with additional fields
3
4import 'express';
5
6declare module 'express' {
7 interface Request {
8 userId?: string;
9 parkZone?: string;
10 securityClearance?: 'visitor' | 'staff' | 'admin';
11 }
12}
13
14// Now in the application code:
15// app.use((req, res, next) => {
16// req.userId = 'USR-001'; // OK - TypeScript knows this field
17// req.parkZone = 'zone-a'; // OK
18// req.securityClearance = 'staff'; // OK
19// next();
20// });Declaration files (.d.ts) and the DefinitelyTyped ecosystem are the foundations of working with TypeScript in the real world. Thanks to them, you can use thousands of JavaScript libraries with full type safety - like scientists in Jurassic Park who, thanks to "translation dictionaries," could read even the oldest tablets with information about dinosaurs.