Typescript Foundations / Type Declaration and third party types

Module Augmentation

Module Augmentation allows you to extend or modify existing modules — useful when:

  • You want to add custom typings to a third-party library.

  • You need to extend interfaces, add functions, or override types of an existing module (like a package from node_modules).


🧠 Core Idea

Module augmentation uses the declare module syntax to re-open a module and add types or members to it.


📘 Basic Example

Original module (e.g. from my-lib):

// node_modules/my-lib/index.d.ts
declare module "my-lib" {
  export interface User {
    name: string;
  }
}

➕ Augmenting the module:

// types/my-lib-augmentation.d.ts
import "my-lib";

declare module "my-lib" {
  interface User {
    age: number; // ⬅️ Added property
  }

  export function getUserAge(user: User): number; // ⬅️ New function
}

Now you can use the age property and getUserAge() in your code, and TypeScript will recognize them.


🧩 Real Use Case: Extending Express Request

// types/express/index.d.ts
import "express";

declare module "express-serve-static-core" {
  interface Request {
    user?: { id: string; role: string };
  }
}

Now in your app:

app.get("/profile", (req, res) => {
  console.log(req.user?.id); // ✅ No TypeScript error
});

⚠️ Best Practices

  • Always import the original module first (e.g. import "express";) to ensure the augmentation merges.

  • Put all augmentation files in a types/ folder and include it in tsconfig.json:

{
  "compilerOptions": {
    "typeRoots": ["./types", "./node_modules/@types"]
  }
}

✅ When to Use

Use Case

Augmentation Needed?

Add fields to existing types (like Request in Express)

✅ Yes

Extend a third-party library's exported interface

✅ Yes

Add global types or custom modules

❌ Use .d.ts with global declarations