Skip to content

TypeScript Namespaces

As applications become more complex, the number of variables and functions in the global scope increases dramatically, which can easily lead to naming conflicts. Namespaces are a way in early versions of TypeScript to solve this problem. They allow you to organize related code in a logical grouping, avoiding pollution of the global scope.

Note: In modern TypeScript development, it's recommended to use modules (i.e., ES6's import/export) to organize code rather than namespaces. Modules provide better code isolation and dependency management. However, understanding namespaces is still important because you'll still encounter them in some older codebases or specific scenarios (like writing declaration files for global libraries).

What are Namespaces?

Namespaces provide a way to encapsulate code within a specific scope. You can use the namespace keyword to define a namespace.

typescript
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

In this example, we've placed validation-related interfaces and classes in the Validation namespace.

  • By default, everything in a namespace is private.
  • You must use the export keyword to make members in the namespace (like interfaces, classes, variables, functions) visible externally.

Using Namespaces

To use members in a namespace, you need to access them through the NamespaceName.MemberName syntax.

typescript
// Create an instance of LettersOnlyValidator
let validator = new Validation.LettersOnlyValidator();

console.log(validator.isAcceptable("HelloWorld")); // true
console.log(validator.isAcceptable("12345"));      // false

Multi-file Namespaces

Namespaces can span multiple files. As long as the namespaces in multiple files have the same name, the TypeScript compiler will merge them into a single namespace. This can be useful when organizing large projects.

Validators.ts

typescript
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}

LettersOnlyValidator.ts

typescript
/// <reference path="Validators.ts" />
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

Here, /// <reference path="..." /> is a triple-slash directive that tells the compiler about dependencies between files. This was the way TypeScript managed file dependencies before the module system appeared.

Aliases

To simplify access to deeply nested namespace members, you can use the import keyword to create an alias for them.

typescript
namespace Shapes {
    export namespace Polygons {
        export class Triangle { /* ... */ }
        export class Square { /* ... */ }
    }
}

// Create an alias
import Polygon = Shapes.Polygons;

let sq = new Polygon.Square(); // Use the alias

Important Note: The import here is different from import in ES6 modules. It's only used to create aliases for members in namespaces and doesn't load any files.

Choosing Between Namespaces and Modules

  • Namespaces: Mainly used to organize code in the global scope, managing file dependencies through /// <reference>. Suitable for traditional web application development without a module loader.
  • Modules: Each file is an independent module with its own scope. Dependencies are managed through import and export. This is the recommended approach for modern JavaScript and TypeScript development, fully compatible with Node.js and bundling tools (like Webpack, Vite).

Overall, for new projects, you should prioritize using modules. You only need to deeply understand namespaces when maintaining old projects or interacting with global JavaScript libraries that don't use modules.

Content is for learning and research only.