Modules and namespaces in TypeScript help organize and encapsulate code. Modules use the JavaScript import/export system, while namespaces provide a way to organize related code within a shared namespace. Modern TypeScript applications generally prefer modules for code organization.
1. A File Becomes a Module When It Uses import or export
A TypeScript file is treated as a module when it contains a top-level import or export statement. Module files have their own scope, which helps prevent naming conflicts.
import { something } from "./anotherModule";
The imported value can then be used within the file without becoming a global variable.
2. Modules Are Preferred Over Namespaces for Modern Code
Namespaces were traditionally used to organize TypeScript code, especially before ES modules became widely adopted.
namespace MyNamespace {
export const message = "Hello!";
}
For modern applications, TypeScript generally recommends using ES modules instead:
export const message = "Hello!";
Namespaces can still be useful in certain scenarios, such as maintaining older code or organizing global APIs.
3. TypeScript Supports Module Augmentation
Module augmentation allows you to add declarations to an existing module. It is commonly used to extend the types provided by third-party libraries.
// Original module
export interface User {
name: string;
}
// Augmentation
declare module "./user" {
interface User {
age: number;
}
}
After augmentation, TypeScript treats User as having both name and age.
Module augmentation changes the type declarations. It does not automatically add runtime functionality to the module.
4. Namespaces Can Be Nested
Namespaces can be nested to create a hierarchical organization of related code.
export namespace OuterNamespace {
export namespace InnerNamespace {
export const message = "Hello from nested namespace!";
}
}
The nested value can be accessed as:
console.log(
OuterNamespace.InnerNamespace.message
);
The namespace keyword is the modern syntax; module was an older alias for namespaces.
5. Namespaces Can Be Merged
TypeScript supports declaration merging, which allows multiple declarations of the same namespace to be combined.
// file1.ts
namespace MyNamespace {
export const x = 10;
}
// file2.ts
namespace MyNamespace {
export const y = 20;
}
The merged namespace contains both x and y.
This pattern is primarily associated with script/global-style namespaces and legacy TypeScript patterns rather than modern ES module organization.
6. Modules Can Re-Export Members
A module can re-export members from other modules, allowing you to create a central entry point.
// math.ts
export { add } from "./addition";
export { subtract } from "./subtraction";
Another module can then import both functions from math.ts:
import { add, subtract } from "./math";
This pattern is commonly used to create a public API for a library or application module.
7. Global Namespaces Can Be Used Without Imports
A namespace declared in the global scope can be accessed directly without an import statement.
namespace MyNamespace {
export const message = "Hello!";
}
console.log(MyNamespace.message);
Because MyNamespace is in the global scope, it can be accessed directly.
However, a namespace declared inside an ES module is not automatically available globally.
8. Modules Can Be Dynamically Imported
TypeScript supports JavaScript's dynamic import() syntax, which loads a module asynchronously.
const module = await import("./myModule");
module.someFunction();
Dynamic imports are useful for lazy loading, where code is loaded only when it is needed.
Because import() returns a Promise, it can also be used without await:
import("./myModule").then((module) => {
module.someFunction();
});
9. Modules and Namespaces Have Different Organization Models
ES modules are based on module files and use import and export to explicitly share code.
Namespaces provide a named scope that can organize related declarations and, in some cases, span multiple files through declaration merging.
For modern TypeScript applications, ES modules are generally the preferred approach because they integrate directly with the JavaScript module system and modern build tools.