Skip to main content

Module 12: Declaration Files (.d.ts)

Declaration files provide type definitions for JavaScript libraries, enabling TypeScript to understand their structure and provide type checking.


1. What are Declaration Files?

Declaration files (.d.ts) contain type declarations without implementation.

// math.d.ts
export function add(a: number, b: number): number;
export function subtract(a: number, b: number): number;

export class Calculator {
add(a: number, b: number): number;
multiply(a: number, b: number): number;
}

2. Using Declaration Files

For npm Packages

# Install types from DefinitelyTyped
npm install --save-dev @types/node
npm install --save-dev @types/express
npm install --save-dev @types/lodash

Manual Declaration Files

// myLibrary.d.ts
declare module "my-library" {
export function doSomething(): void;
export class MyClass {
constructor(value: string);
getValue(): string;
}
}

// app.ts
import { doSomething, MyClass } from "my-library";

doSomething();
let instance = new MyClass("hello");

3. Declaring Global Variables

// global.d.ts
declare var jQuery: (selector: string) => any;
declare var $: (selector: string) => any;

// app.ts
jQuery("#app").hide();
$("#header").show();

4. Declaring Global Functions

// declarations.d.ts
declare function greet(name: string): string;
declare function sum(...numbers: number[]): number;

// app.ts
let greeting = greet("Alice");
let total = sum(1, 2, 3, 4, 5);

5. Declaring Classes

// lib.d.ts
declare class EventEmitter {
on(event: string, listener: Function): this;
emit(event: string, ...args: any[]): boolean;
removeListener(event: string, listener: Function): this;
}

// app.ts
let emitter = new EventEmitter();
emitter.on("data", (data) => console.log(data));

6. Declaring Namespaces

// jQuery.d.ts
declare namespace JQuery {
interface Ajax {
url: string;
method: string;
success?: (data: any) => void;
}
}

declare function $(selector: string): JQuery.Element;

declare namespace $ {
function ajax(settings: JQuery.Ajax): void;
}

// app.ts
$.ajax({
url: "/api/users",
method: "GET",
success: (data) => console.log(data)
});

7. Module Augmentation

Extend existing type definitions.

// express.d.ts (existing)
declare module "express" {
interface Request {
// existing properties
}
}

// custom.d.ts (your augmentation)
import "express";

declare module "express" {
interface Request {
user?: {
id: number;
name: string;
};
}
}

// app.ts
import { Request, Response } from "express";

function handler(req: Request, res: Response) {
console.log(req.user?.name); // ✅ OK
}

8. Ambient Declarations

Declare types without importing.

// ambient.d.ts
declare const API_URL: string;
declare const VERSION: string;

declare interface Config {
apiKey: string;
environment: "dev" | "prod";
}

declare type ID = string | number;

// app.ts (no import needed)
console.log(API_URL);
let config: Config = {
apiKey: "abc123",
environment: "dev"
};

9. Triple-Slash Directives

Reference other declaration files.

/// <reference path="./types.d.ts" />
/// <reference types="node" />

// Now types from referenced files are available

10. Creating Declaration Files

From TypeScript Source

// calculator.ts
export class Calculator {
add(a: number, b: number): number {
return a + b;
}

multiply(a: number, b: number): number {
return a * b;
}
}

Compile with declaration flag:

tsc calculator.ts --declaration

Generated calculator.d.ts:

export declare class Calculator {
add(a: number, b: number): number;
multiply(a: number, b: number): number;
}

11. Declaration File Best Practices

Example: Complete Library Definition

// mylib.d.ts

// Export types
export interface Options {
timeout?: number;
retries?: number;
}

export type Callback = (error: Error | null, result?: any) => void;

// Export functions
export function request(url: string, options?: Options): Promise<any>;
export function requestSync(url: string, options?: Options): any;

// Export class
export class Client {
constructor(apiKey: string);
get(path: string): Promise<any>;
post(path: string, data: any): Promise<any>;
}

// Default export
export default class MyLib {
static version: string;
static initialize(config: Options): void;
}

// Namespace for additional utilities
export namespace Utils {
function parse(data: string): any;
function stringify(obj: any): string;
}

12. Conditional Types in Declarations

// utils.d.ts
export type IsArray<T> = T extends any[] ? true : false;
export type Flatten<T> = T extends Array<infer U> ? U : T;
export type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;

export function flatten<T>(arr: T): Flatten<T>;
export function unwrap<T>(promise: T): Awaited<T>;

13. Generic Declarations

// collection.d.ts
export interface Collection<T> {
add(item: T): void;
remove(item: T): boolean;
find(predicate: (item: T) => boolean): T | undefined;
toArray(): T[];
}

export class ArrayList<T> implements Collection<T> {
constructor(items?: T[]);
add(item: T): void;
remove(item: T): boolean;
find(predicate: (item: T) => boolean): T | undefined;
toArray(): T[];
}

14. UMD Module Declarations

Support both CommonJS and AMD.

// library.d.ts
export as namespace myLib;

export interface Config {
apiKey: string;
}

export function initialize(config: Config): void;

export class Client {
constructor();
request(url: string): Promise<any>;
}

Usage:

// ES6 module
import * as myLib from "my-library";
myLib.initialize({ apiKey: "abc" });

// Global (script tag)
myLib.initialize({ apiKey: "abc" });

15. Publishing Type Definitions

In Your Package

// package.json
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
]
}

To DefinitelyTyped

# Clone DefinitelyTyped
git clone https://github.com/DefinitelyTyped/DefinitelyTyped.git

# Create your type definition
cd DefinitelyTyped/types
mkdir my-library
cd my-library

# Create files
touch index.d.ts
touch tsconfig.json
touch tslint.json
// index.d.ts
declare module "my-library" {
export function doSomething(): void;
}

16. Real-World Example: API Client Types

// api-client.d.ts
export interface APIConfig {
baseURL: string;
timeout?: number;
headers?: Record<string, string>;
}

export interface APIResponse<T> {
data: T;
status: number;
statusText: string;
headers: Record<string, string>;
}

export interface APIError {
message: string;
code: string;
status: number;
}

export class APIClient {
constructor(config: APIConfig);

get<T = any>(url: string, config?: Partial<APIConfig>): Promise<APIResponse<T>>;
post<T = any>(url: string, data?: any, config?: Partial<APIConfig>): Promise<APIResponse<T>>;
put<T = any>(url: string, data?: any, config?: Partial<APIConfig>): Promise<APIResponse<T>>;
delete<T = any>(url: string, config?: Partial<APIConfig>): Promise<APIResponse<T>>;
}

export interface RequestInterceptor {
onRequest(config: APIConfig): APIConfig | Promise<APIConfig>;
onError(error: APIError): any;
}

export interface ResponseInterceptor {
onResponse<T>(response: APIResponse<T>): APIResponse<T> | Promise<APIResponse<T>>;
onError(error: APIError): any;
}

Key Takeaways

Declaration files provide types without implementations
✅ Use @types packages for popular libraries
Ambient declarations for global variables/functions
Module augmentation extends existing types
Triple-slash directives reference dependencies
✅ Generate .d.ts with --declaration flag
✅ Publish types with your package or to DefinitelyTyped


Practice Exercises

Exercise 1: Create Declaration File

Write a declaration file for a simple library:

// mymath.d.ts
declare module "mymath" {
export function add(a: number, b: number): number;
export function multiply(a: number, b: number): number;

export class Calculator {
constructor();
calculate(expression: string): number;
}
}

Exercise 2: Augment Express Types

import "express";

declare module "express" {
interface Request {
userId?: string;
timestamp?: Date;
}
}

Exercise 3: Create Global Types

// global.d.ts
declare global {
interface Window {
API_KEY: string;
config: {
debug: boolean;
version: string;
};
}
}

export {};

Next Steps

In Module 13, we'll learn TypeScript with React, covering component types, hooks, and patterns for building type-safe React applications.