bugl
bugl
HomeLearnPatternsSearch
HomeLearnPatternsSearch

Loading lesson path

Learn/TypeScript/TypeScript Core
TypeScript•TypeScript Core

TypeScript Namespaces

Concept visual

TypeScript Namespaces

Pointer walk
two pointers
leftright102132436485116
left=0
right=6
1
3

Start at both ends

Understanding TypeScript Namespaces

TypeScript namespaces (previously known as "internal modules") provide a powerful way to organize code and prevent naming conflicts by creating a container for related functionality. They help in structuring large codebases and managing scope in a clean, maintainable way.

Key Concepts

Logical Grouping

: Organize related code into named containers

Scope Management

: Control the visibility of code elements

Name Collision Prevention

: Avoid conflicts between similarly named components

Code Organization

: Structure large applications in a hierarchical manner

When to Use Namespaces

Organizing code in large legacy applications

Working with global libraries

When migrating from older JavaScript codebases

When working with code that needs to be available globally

Note:

While namespaces are still fully supported in TypeScript, modern applications typically use ES modules (import/export) for better modularity and tree-shaking support. However, understanding namespaces is valuable for maintaining legacy codebases and certain library development scenarios.

Basic Namespace Syntax

Creating and Using Namespaces

A namespace is defined using the namespace keyword:

Example namespace Validation {

// Everything inside this block belongs to the Validation namespace

// Export things you want to make available outside the namespace export interface StringValidator {
isValid(s: string): boolean;
}
// This is private to the namespace (not exported)
const lettersRegexp = /^[A-Za-z]+$/;
// Exported class - available outside the namespace export class LettersValidator implements StringValidator {
isValid(s: string): boolean {
return lettersRegexp.test(s);
}
}
// Another exported class export class ZipCodeValidator implements StringValidator {
isValid(s: string): boolean {
return /^[0-9]+$/.test(s) && s.length === 5;
}
}
}
// Using the namespace members let letterValidator = new Validation.LettersValidator();
let zipCodeValidator = new Validation.ZipCodeValidator();
console.log(letterValidator.isValid("Hello")); // true console.log(letterValidator.isValid("Hello123")); // false console.log(zipCodeValidator.isValid("12345")); // true console.log(zipCodeValidator.isValid("1234")); // false - wrong length

Advanced Namespace Features

Nested Namespaces

Namespaces can be nested to create hierarchical organization:

Example namespace App {
export namespace Utils {
export function log(msg: string): void {
console.log(`[LOG]: ${msg}`);
}
export function error(msg: string): void {
console.error(`[ERROR]: ${msg}`);
}
}
export namespace Models {
export interface User {
id: number;
name: string;
email: string;
}
export class UserService {
getUser(id: number): User {
return { id, name: "John Doe", email: "john@example.com" };
}
}
}
}

// Using nested namespaces

App.Utils.log("Application starting");
const userService = new App.Models.UserService();
const user = userService.getUser(1);
App.Utils.log(`User loaded: ${user.name}`);

// This would be a type error in TypeScript

// App.log("directly accessing log"); // Error - log is not a direct member of App

Namespace Aliases

You can create aliases for namespaces or their members to make long names more manageable:

Example namespace VeryLongNamespace {
export namespace DeeplyNested {
export namespace Components {
export class Button {
display(): void {
console.log("Button displayed");
}
}
export class TextField {
display(): void {
console.log("TextField displayed");
}
}
}
}
}
// Without alias - very verbose const button1 = new VeryLongNamespace.DeeplyNested.Components.Button();
button1.display();
// With namespace alias import Components = VeryLongNamespace.DeeplyNested.Components;
const button2 = new Components.Button();
button2.display();
// With specific member alias import Button = VeryLongNamespace.DeeplyNested.Components.Button;
const button3 = new Button();
button3.display();

Working with Multi-file Namespaces

Splitting Namespaces Across Files

Large applications often require splitting code across multiple files. TypeScript namespaces can be split across files and combined at compile time using reference comments:

Using Reference Comments

Reference comments help TypeScript understand the relationship between files: validators.ts file:

Example namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
}

Formula

letters - validator.ts file (extends Validation namespace):

Example

/// <reference path="validators.ts" />

namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersValidator implements StringValidator {
isValid(s: string): boolean {
return lettersRegexp.test(s);
}
}
}

Formula

zipcode - validator.ts file:

Example

/// <reference path="validators.ts" />

namespace Validation {
const zipCodeRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isValid(s: string): boolean {
return zipCodeRegexp.test(s) && s.length === 5;
}
}
}

main.ts file:

Example

/// <reference path="validators.ts" />

Formula

/// < reference path ="letters - validator.ts" />
/// < reference path ="zipcode - validator.ts" />

// Now you can use the validators from multiple files let validators: { [s: string]: Validation.StringValidator } = {};

validators["letters"] = new Validation.LettersValidator();
validators["zipcode"] = new Validation.ZipCodeValidator();
// Some samples to validate let strings = ["Hello", "98052", "101"];
// Validate each strings.forEach(s => {
for (let name in validators) {
console.log(`"${s}" - ${validators[name].isValid(s) ? "matches" : "does not match"} ${name}`);
}
});

To compile these files into a single JavaScript file, use:

Example tsc --outFile sample.js main.ts Namespaces vs. Modules

Key Differences

Understanding when to use namespaces versus modules is crucial for TypeScript development: Modules are the preferred way to organize code in modern TypeScript applications Namespaces are still useful for specific scenarios like declaration merging or working with legacy code

Formula

Modules have better tooling support and tree - shaking capabilities

Namespaces can be useful for creating global libraries Here's a comparison of when to use namespaces versus ES modules:

Comparison Table

Previous

TypeScript Literal Types

Next

TypeScript Index Signatures