TypeScript Namespaces
Organizing code with internal modules
📦 What are Namespaces?
Namespaces are TypeScript's way of organizing and grouping related code into logical containers, preventing naming conflicts and providing a structured approach to code organization in large applications.
// Simple namespace example
namespace Utilities {
export function log(message: string) {
console.log(message);
}
}
Utilities.log('Hello from namespace!');
Output:
Hello from namespace!
Key Namespace Concepts
Basic Namespace
Group related functionality
namespace MyApp {
export class User {}
}
Nested Namespaces
Create hierarchical structure
namespace App {
export namespace Utils {}
}
Export Members
Make items publicly accessible
namespace Math {
export function add() {}
}
Aliases
Create shortcuts for namespaces
import Utils = App.Utilities;
Utils.log('message');
🔹 Basic Namespace
Create a simple namespace to group related code:
// Define a namespace
namespace StringUtilities {
// Export function to make it accessible
export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
export function reverse(str: string): string {
return str.split('').reverse().join('');
}
// Private function (not exported)
function helper() {
return 'This is private';
}
}
// Using namespace members
console.log(StringUtilities.capitalize('hello')); // Output: Hello
console.log(StringUtilities.reverse('world')); // Output: dlrow
// This would cause an error (helper is not exported)
// StringUtilities.helper();
Output:
Hello
dlrow
🔹 Nested Namespaces
Create hierarchical organization with nested namespaces:
namespace App {
export namespace Models {
export class User {
constructor(public name: string, public age: number) {}
}
export class Product {
constructor(public title: string, public price: number) {}
}
}
export namespace Services {
export class UserService {
getUser(id: number) {
return new Models.User('John', 30);
}
}
export class ProductService {
getProduct(id: number) {
return new Models.Product('Laptop', 999);
}
}
}
}
// Using nested namespaces
const user = new App.Models.User('Alice', 25);
const userService = new App.Services.UserService();
const fetchedUser = userService.getUser(1);
console.log(fetchedUser.name); // Output: John
Output:
John
🔹 Multi-file Namespaces
Split namespaces across multiple files:
// File: validation.ts
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
}
// File: lettersValidator.ts
/// <reference path="validation.ts" />
namespace Validation {
export class LettersOnlyValidator implements StringValidator {
isValid(s: string): boolean {
return /^[A-Za-z]+$/.test(s);
}
}
}
// File: numbersValidator.ts
/// <reference path="validation.ts" />
namespace Validation {
export class NumbersOnlyValidator implements StringValidator {
isValid(s: string): boolean {
return /^[0-9]+$/.test(s);
}
}
}
// Usage
let lettersValidator = new Validation.LettersOnlyValidator();
console.log(lettersValidator.isValid('Hello')); // true
console.log(lettersValidator.isValid('Hello123')); // false
🔹 Namespace Aliases
Create shorter names for deeply nested namespaces:
namespace Company {
export namespace Department {
export namespace Engineering {
export class Developer {
constructor(public name: string) {}
code() {
return `${this.name} is coding`;
}
}
}
}
}
// Without alias (verbose)
let dev1 = new Company.Department.Engineering.Developer('Alice');
// With alias (cleaner)
import Dev = Company.Department.Engineering.Developer;
let dev2 = new Dev('Bob');
console.log(dev2.code()); // Output: Bob is coding
// Alias for nested namespace
import Eng = Company.Department.Engineering;
let dev3 = new Eng.Developer('Charlie');
Output:
Bob is coding
🔹 Namespace vs Modules
Understanding when to use namespaces vs ES6 modules:
// ❌ Namespace (older approach)
namespace MathUtils {
export function add(a: number, b: number) {
return a + b;
}
}
// ✅ ES6 Module (modern approach - preferred)
// File: mathUtils.ts
export function add(a: number, b: number) {
return a + b;
}
// File: main.ts
import { add } from './mathUtils';
// When to use Namespaces:
// - Legacy code
// - Global scope organization
// - Browser scripts without module bundler
// When to use Modules:
// - Modern TypeScript projects
// - Node.js applications
// - Projects with module bundlers (Webpack, Rollup)
// - Better tree-shaking and code splitting
🔹 Practical Example
Real-world namespace usage:
namespace Game {
export namespace Characters {
export class Player {
constructor(
public name: string,
public health: number = 100
) {}
attack(target: Enemy) {
target.takeDamage(10);
}
}
export class Enemy {
constructor(
public name: string,
public health: number = 50
) {}
takeDamage(amount: number) {
this.health -= amount;
console.log(`${this.name} took ${amount} damage. Health: ${this.health}`);
}
}
}
export namespace Utils {
export function randomNumber(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export function displayMessage(msg: string) {
console.log(`[GAME]: ${msg}`);
}
}
}
// Using the game namespace
const player = new Game.Characters.Player('Hero');
const enemy = new Game.Characters.Enemy('Goblin');
Game.Utils.displayMessage('Battle started!');
player.attack(enemy);
const damage = Game.Utils.randomNumber(5, 15);
console.log(`Random damage: ${damage}`);
Output:
[GAME]: Battle started!
Goblin took 10 damage. Health: 40
Random damage: 12