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.