What is namespace in TypeScript?
In TypeScript, a namespace (also known as an internal module in older versions) provides a way to logically group code related to a specific feature or concept. Its primary purpose is to organize code and prevent naming conflicts in the global scope, especially in larger applications.
What is a Namespace?
A namespace is an organizational unit that helps in encapsulating code. It allows you to define variables, functions, classes, and interfaces within a designated scope, preventing them from clashing with similarly named entities in other parts of your application or third-party libraries. This is particularly useful in applications that don't use external modules and rely on a global scope, such as those targeting older browser environments without native module support.
You define a namespace using the namespace keyword, followed by the name of your namespace.
namespace MyUtilities {
export function greet(name: string): string {
return `Hello, ${name}`;
}
export const PI = 3.14159;
}
// To access members, use the namespace name:
console.log(MyUtilities.greet('Alice')); // Output: Hello, Alice
console.log(MyUtilities.PI); // Output: 3.14159
Exporting Members
By default, members (functions, variables, classes, interfaces) declared within a namespace are private to that namespace. To make them accessible from outside, you must explicitly use the export keyword.
namespace Validation {
const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
export function isValidEmail(email: string): boolean {
return emailRegex.test(email);
}
export class Validator {
isValid(input: string): boolean {
// Some validation logic
return input.length > 5;
}
}
}
// Accessing exported members
console.log(Validation.isValidEmail('test@example.com')); // true or false
let textValidator = new Validation.Validator();
console.log(textValidator.isValid('hello world')); // true
Nested Namespaces
Namespaces can be nested within each other, providing a hierarchical structure for organizing related code. This allows for even finer-grained organization.
namespace MyApplication {
export namespace Data {
export interface User {
id: number;
name: string;
}
export function fetchUsers(): User[] {
return [{ id: 1, name: 'John Doe' }];
}
}
export namespace UI {
export function renderUserList(users: MyApplication.Data.User[]): void {
users.forEach(user => console.log(`- ${user.name}`));
}
}
}
const users = MyApplication.Data.fetchUsers();
MyApplication.UI.renderUserList(users);
Aliases with `import`
To simplify access to deeply nested or long namespace names, you can use the import keyword to create an alias (not to be confused with ES module imports).
namespace Geometries {
export namespace Shapes {
export class Circle { /* ... */ }
export class Square { /* ... */ }
}
}
import Shapes = Geometries.Shapes;
let circle = new Shapes.Circle();
let square = new Shapes.Square();
Namespaces vs. Modules
While namespaces provide an excellent way to organize code, modern TypeScript development heavily favors ES Modules (using import and export statements at the top level of files). Namespaces are generally used in applications that historically targeted environments without native module loaders, or when migrating older JavaScript codebases.
- Namespaces (Internal Modules): Group code within a global scope, often compiled into a single JavaScript file. Useful for avoiding global pollution in non-module environments.
- Modules (External Modules): Each file is a module, with its own scope. They explicitly
importandexportmembers between files. This is the standard for modern web and Node.js development.
For new projects, it is strongly recommended to use ES Modules for code organization due to better tooling support, clearer dependency management, and compatibility with the broader JavaScript ecosystem.