TypeScript Modules and Namespaces

TypeScript is a superset of JavaScript that adds static types and other powerful features to the language. One of the key aspects of TypeScript is its ability to organize and modularize code through the use of modules and namespaces. This chapter will explore these concepts in detail, from the basics to advanced usage, providing comprehensive explanations and examples along the way.

Understanding Modules

Modules are a way to encapsulate and organize code into separate files and reuse them across the application. They help in managing dependencies, avoiding global scope pollution, and making the code more maintainable.

Basic Syntax

In TypeScript, each file is considered a module. Modules can export and import functionality from other modules using export and import keywords.

Exporting from a Module

You can export variables, functions, classes, or interfaces from a module.

				
					// mathUtils.ts
export function add(a: number, b: number): number {
  return a + b;
}

export function subtract(a: number, b: number): number {
  return a - b;
}

				
			

Importing a Module

You can import the exported functionality into another module.

				
					// main.ts
import { add, subtract } from './mathUtils';

console.log(add(5, 3));       // Output: 8
console.log(subtract(5, 3));  // Output: 2
				
			

Explanation:

  • mathUtils.ts exports two functions, add and subtract.
  • main.ts imports these functions and uses them.

Default Exports

A module can have a single default export, which can be a variable, function, class, or object.

				
					// logger.ts
export default function log(message: string): void {
  console.log(message);
}
				
			
				
					// app.ts
import log from './logger';

log('Hello, TypeScript!');  // Output: Hello, TypeScript!
				
			

Explanation:

  • logger.ts exports a default function log.
  • app.ts imports this default function and uses it to log a message.

Named Exports vs. Default Exports

You can mix named exports and default exports in a module.

				
					// utilities.ts
export function greet(name: string): string {
  return `Hello, ${name}!`;
}

export default function farewell(name: string): string {
  return `Goodbye, ${name}!`;
}
				
			
				
					// index.ts
import farewell, { greet } from './utilities';

console.log(greet('Alice'));     // Output: Hello, Alice!
console.log(farewell('Alice'));  // Output: Goodbye, Alice!
				
			

Explanation:

  • utilities.ts exports a named function greet and a default function farewell.
  • index.ts imports both the named and default exports and uses them.

Advanced Module Features

Re-exporting

You can re-export functionality from one module in another module.

				
					// mathOperations.ts
export { add, subtract } from './mathUtils';
				
			
				
					// app.ts
import { add, subtract } from './mathOperations';

console.log(add(10, 5));       // Output: 15
console.log(subtract(10, 5));  // Output: 5
				
			

Explanation:

  • mathOperations.ts re-exports the functions add and subtract from mathUtils.ts.
  • app.ts imports these re-exported functions and uses them.

Importing Everything from a Module

You can import all exports from a module as a single object.

				
					// constants.ts
export const PI = 3.14;
export const E = 2.71;
				
			
				
					// main.ts
import * as constants from './constants';

console.log(constants.PI);  // Output: 3.14
console.log(constants.E);   // Output: 2.71
				
			

Explanation:

  • constants.ts exports two constants, PI and E.
  • main.ts imports everything from constants.ts as a single object constants and accesses the constants.

Dynamic Imports

You can dynamically import modules at runtime using import().

				
					// utils.ts
export function sayHello() {
  console.log('Hello!');
}
				
			
				
					// main.ts
async function loadUtils() {
  const utils = await import('./utils');
  utils.sayHello();  // Output: Hello!
}

loadUtils();
				
			

Explanation:

  • utils.ts exports a function sayHello.
  • main.ts dynamically imports utils.ts using import(), and then calls the sayHello function.

Understanding Namespaces

Namespaces in TypeScript are a way to organize and group related code. They provide a way to avoid global scope pollution by encapsulating code within a namespace. Unlike modules, namespaces can be nested and declared multiple times.

Basic Syntax

You can declare a namespace using the namespace keyword.

				
					namespace MathUtils {
  export function add(a: number, b: number): number {
    return a + b;
  }

  export function subtract(a: number, b: number): number {
    return a - b;
  }
}

console.log(MathUtils.add(5, 3));       // Output: 8
console.log(MathUtils.subtract(5, 3));  // Output: 2
				
			

Explanation:

  • MathUtils namespace contains two functions, add and subtract.
  • The functions are accessed using the namespace name MathUtils.

Nested Namespaces

You can nest namespaces to further organize code.

				
					namespace Utilities {
  export namespace Math {
    export function add(a: number, b: number): number {
      return a + b;
    }

    export function subtract(a: number, b: number): number {
      return a - b;
    }
  }

  export namespace String {
    export function toUpperCase(str: string): string {
      return str.toUpperCase();
    }

    export function toLowerCase(str: string): string {
      return str.toLowerCase();
    }
  }
}

console.log(Utilities.Math.add(10, 5));        // Output: 15
console.log(Utilities.String.toUpperCase('hello'));  // Output: HELLO
				
			

Explanation:

  • Utilities namespace contains two nested namespaces: Math and String.
  • The Math namespace contains two functions, add and subtract.
  • The String namespace contains two functions, toUpperCase and toLowerCase.
  • The functions are accessed using the nested namespace names.

Merging Namespaces

You can declare the same namespace multiple times, and TypeScript will merge them.

				
					namespace App {
  export function initialize() {
    console.log('App initialized');
  }
}

namespace App {
  export function shutdown() {
    console.log('App shutdown');
  }
}

App.initialize();  // Output: App initialized
App.shutdown();   // Output: App shutdown
				
			

Explanation:

  • The App namespace is declared twice, with each declaration adding a new function.
  • TypeScript merges the declarations into a single namespace.
  • The functions are accessed using the App namespace.

Combining Modules and Namespaces

You can combine modules and namespaces to leverage the benefits of both.

Namespaces in Modules

You can declare a namespace inside a module.

				
					// shapes.ts
export namespace Shapes {
  export class Circle {
    constructor(public radius: number) {}

    area(): number {
      return Math.PI * this.radius * this.radius;
    }
  }

  export class Square {
    constructor(public size: number) {}

    area(): number {
      return this.size * this.size;
    }
  }
}
				
			
				
					// main.ts
import { Shapes } from './shapes';

const circle = new Shapes.Circle(5);
console.log(circle.area());  // Output: 78.53981633974483

const square = new Shapes.Square(4);
console.log(square.area());  // Output: 16
				
			

Explanation:

  • shapes.ts declares a Shapes namespace inside a module.
  • The Shapes namespace contains two classes, Circle and Square.
  • main.ts imports the Shapes namespace and uses the classes to create instances and calculate areas.

Global Augmentation

You can augment global namespaces by merging them with module declarations.

				
					// globals.d.ts
declare namespace NodeJS {
  interface Global {
    appName: string;
  }
}

// app.ts
global.appName = 'MyApp';

console.log(global.appName);  // Output: MyApp
				
			

Explanation:

  • globals.d.ts declares an augmentation of the NodeJS.Global interface to include a new property appName.
  • app.ts sets the global.appName property and logs it to the console.

Modules and namespaces in TypeScript provide powerful tools for organizing and modularizing code. Modules offer a way to encapsulate and reuse code across files, while namespaces allow for grouping related code and avoiding global scope pollution. By understanding and utilizing these features, you can write more maintainable, scalable, and type-safe TypeScript code. Happy coding! ❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India