TypeScript Module Augmentation
Module augmentation adds declarations to a module that already has them. A declare module block with the module path extends an interface from another file.
The shop.ts file
The base module declares a Cart interface with two members and a function that describes a cart.
export interface Cart {
id: number;
itemCount: number;
}
export function describeCart(cart: Cart): string {
return 'Cart ' + cart.id + ' holds ' + cart.itemCount + ' items';
}The cart-extras.ts file
The augmentation file declares the same module path and adds a discountCode member to Cart. The helper function reads the added member.
import type { Cart } from './shop';
declare module './shop' {
interface Cart {
discountCode: string;
}
}
export function applyDiscount(cart: Cart): string {
return cart.discountCode + ' applied to cart ' + cart.id;
}Using the added member
The consumer builds a cart with all three members and passes it to functions from both files. The base function accepts the cart because the interfaces merged.
import { describeCart } from './shop';
import { applyDiscount } from './cart-extras';
const cart = { id: 7, itemCount: 3, discountCode: 'SAVE10' };
console.log(describeCart(cart));
console.log(applyDiscount(cart));Example
import { describeCart } from './shop';
import type { Cart } from './shop';
import { applyDiscount } from './cart-extras';
const carts: Cart[] = [
{ id: 1, itemCount: 2, discountCode: 'SAVE10' },
{ id: 2, itemCount: 5, discountCode: 'HALF' },
];
for (const cart of carts) {
console.log(describeCart(cart));
console.log(applyDiscount(cart));
}Key points
- A declare module block names the target module by its import path.
- An interface declared inside the block merges with the interface of the same name in the target module.
- The added member is usable in every file that imports the module, once the augmentation file is part of the program.
- An augmentation must live in a module file.
- A module file is a file with its own imports or exports.
In this example, each cart is typed with the augmented Cart interface, so the discountCode member is required and checked. The base module function and the augmentation helper both read the same merged type.
Note
The augmentation changes the types only, and the runtime code of the target module stays unchanged.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท TypeScript Playground
Exercise
Where must a module augmentation live?