Bird
Raised Fist0
Typescriptprogramming~10 mins

Module augmentation syntax in Typescript - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Module augmentation syntax
Import or declare module
↓
Use 'declare module' with same module name
↓
Add new types, interfaces, or values inside
↓
Merge with original module
↓
Use augmented module in code
Module augmentation lets you add new types or values to an existing module by declaring the same module name again and adding new content inside.
Execution Sample
Typescript
import { User } from './user';

declare module './user' {
  interface User {
    age: number;
  }
}

const u: User = { name: 'Anna', age: 30 };
This code adds an 'age' property to the existing 'User' interface from './user' module.
Execution Table
StepActionEvaluationResult
1Import User interface from './user'User has property 'name: string'User interface available with 'name'
2Declare module './user' againModule found, ready to augmentModule augmentation started
3Add 'age: number' property to User interfaceUser interface now has 'name' and 'age'User interface augmented
4Create constant u of type Useru must have 'name' and 'age'u = { name: 'Anna', age: 30 } is valid
5Use u in codeu.name = 'Anna', u.age = 30No errors, augmentation works
💡 All steps complete, module augmentation applied successfully
Variable Tracker
VariableStartAfter Step 3After Step 4Final
User interface{ name: string }{ name: string, age: number }{ name: string, age: number }{ name: string, age: number }
uundefinedundefined{ name: 'Anna', age: 30 }{ name: 'Anna', age: 30 }
Key Moments - 3 Insights
Why can we declare the same module name twice?
Because TypeScript merges declarations with the same module name, allowing augmentation instead of replacement, as shown in step 2 and 3.
Does augmentation change the original module file?
No, augmentation only adds types at compile time without modifying the original module code, as seen in step 3.
Why must the augmented interface include all properties when creating 'u'?
Because after augmentation, the interface expects all properties combined, so 'u' must have both 'name' and 'age' (step 4).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what properties does the User interface have after step 3?
AOnly 'name'
BOnly 'age'
C'name' and 'age'
DNo properties
💡 Hint
Check the 'Evaluation' column at step 3 in the execution table
At which step is the constant 'u' created with both 'name' and 'age'?
AStep 3
BStep 4
CStep 2
DStep 5
💡 Hint
Look at the 'Action' column for when 'u' is created in the execution table
If we remove the augmentation block, what happens when creating 'u' with 'age' property?
AError, 'age' is not defined in User
B'age' becomes optional
CNo error, 'age' is allowed
DUser interface is empty
💡 Hint
Refer to variable_tracker showing User interface before augmentation
Concept Snapshot
Module augmentation syntax:
Use 'declare module "module-name"' to add new types or interfaces.
TypeScript merges these with the original module.
Allows extending existing types without changing original code.
Useful for adding properties or functions to third-party modules.
Full Transcript
Module augmentation in TypeScript lets you add new types or properties to an existing module by declaring the same module name again with 'declare module'. This merges your additions with the original module's types. For example, you can add an 'age' property to a 'User' interface imported from another file. The process involves importing the module, declaring the module again with the same name, adding new properties inside, and then using the augmented types in your code. This does not change the original module file but extends its types at compile time. When creating objects of the augmented type, you must include all original and added properties. This technique is helpful to extend third-party modules safely.

Practice

(1/5)
1. What is the main purpose of module augmentation in TypeScript?
easy
A. To create a new module from scratch
B. To delete types from a module
C. To add or extend types in an existing module without modifying its original source code
D. To convert JavaScript code into TypeScript

Solution

  1. Step 1: Understand module augmentation purpose

    Module augmentation allows adding or extending types in existing modules without changing their original code.
  2. Step 2: Compare options

    Only To add or extend types in an existing module without modifying its original source code correctly describes this purpose. Options A, C, and D describe unrelated actions.
  3. Final Answer:

    To add or extend types in an existing module without modifying its original source code -> Option C
  4. Quick Check:

    Module augmentation = extend existing types [OK]
Hint: Module augmentation means adding types to existing modules [OK]
Common Mistakes:
  • Thinking it creates new modules
  • Confusing augmentation with deleting types
  • Assuming it converts JS to TS
2. Which of the following is the correct syntax to start a module augmentation for a module named "my-library"?
easy
A. module augment "my-library" { /* augmentation here */ }
B. declare module "my-library" { /* augmentation here */ }
C. augment module "my-library" { /* augmentation here */ }
D. module "my-library" augment { /* augmentation here */ }

Solution

  1. Step 1: Recall correct syntax for module augmentation

    The correct syntax uses declare module "module-name" { ... } to augment a module.
  2. Step 2: Check options

    Only declare module "my-library" { /* augmentation here */ } matches this syntax exactly. Others use invalid keywords or order.
  3. Final Answer:

    declare module "my-library" { /* augmentation here */ } -> Option B
  4. Quick Check:

    Use declare module "name" for augmentation [OK]
Hint: Start with 'declare module "module-name"' for augmentation [OK]
Common Mistakes:
  • Using wrong keywords like 'augment' or 'module augment'
  • Incorrect order of keywords
  • Omitting 'declare'
3. Given the following code, what will be the output of console.log(myLib.newFunction());?
import * as myLib from "my-library";

declare module "my-library" {
  export function newFunction(): string;
}

myLib.newFunction = () => "Hello from augmentation!";

console.log(myLib.newFunction());
medium
A. "Hello from augmentation!"
B. TypeError: myLib.newFunction is not a function
C. undefined
D. SyntaxError

Solution

  1. Step 1: Understand augmentation effect

    The module augmentation adds a new function type declaration to "my-library". Then the function is assigned an implementation.
  2. Step 2: Check runtime behavior

    Calling myLib.newFunction() runs the assigned arrow function returning the string "Hello from augmentation!".
  3. Final Answer:

    "Hello from augmentation!" -> Option A
  4. Quick Check:

    Augmented function runs and returns string [OK]
Hint: Augmented functions can be assigned and called normally [OK]
Common Mistakes:
  • Assuming augmentation adds runtime code automatically
  • Expecting TypeError because function was not originally present
  • Confusing type declaration with implementation
4. Identify the error in this module augmentation code:
declare module "utils" {
  export interface Config {
    timeout: number;
  }
}

declare module "utils" {
  export interface Config {
    retries: number;
  }
}

const config: Config = { timeout: 1000, retries: 3 };
medium
A. No error, code is correct
B. The interface Config is declared twice without merging
C. The module name "utils" is invalid
D. The variable config is missing import from "utils"

Solution

  1. Step 1: Check interface merging

    Interfaces with the same name in module augmentation merge correctly, so no error there.
  2. Step 2: Check usage of Config

    The variable config uses Config but does not import or reference it properly, causing an error.
  3. Final Answer:

    The variable config is missing import from "utils" -> Option D
  4. Quick Check:

    Missing import causes error, not interface duplication [OK]
Hint: Always import types before using them outside modules [OK]
Common Mistakes:
  • Thinking interface redeclaration causes error
  • Ignoring missing imports
  • Assuming module name is invalid
5. You want to add a new method logInfo(message: string): void to the existing Logger class from a third-party module "logger-lib" without modifying its source. Which is the correct way to do this using module augmentation?
hard
A. declare module "logger-lib" { interface Logger { logInfo(message: string): void; } } Logger.prototype.logInfo = function(message) { console.log(message); };
B. module "logger-lib" { class Logger { logInfo(message: string): void {} } }
C. declare module "logger-lib" { class Logger { logInfo(message: string): void {} } }
D. augment module "logger-lib" { interface Logger { logInfo(message: string): void; } }

Solution

  1. Step 1: Use correct module augmentation syntax

    Use declare module "logger-lib" { interface Logger { ... } } to add method signature.
  2. Step 2: Add method implementation to prototype

    Assign the method to Logger.prototype to add runtime behavior without modifying original source.
  3. Final Answer:

    declare module "logger-lib" { interface Logger { logInfo(message: string): void; } } Logger.prototype.logInfo = function(message) { console.log(message); }; -> Option A
  4. Quick Check:

    Declare interface then add method to prototype [OK]
Hint: Declare interface then add method to prototype for augmentation [OK]
Common Mistakes:
  • Using 'module' instead of 'declare module'
  • Declaring class instead of interface in augmentation
  • Forgetting to add method implementation
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard