Standard ES modules — import/export — are TypeScript's normal, recommended way to organize code across files, working identically to how the rest of the JavaScript ecosystem does it. namespace is an older, TypeScript-only construct predating ES modules in the JavaScript ecosystem, using dot-separated global names to group code; the official TypeScript documentation itself now recommends modules for ordinary application code, reserving namespaces for narrower cases like organizing global ambient type declarations.
ES modules: the standard, recommended approach
Any file with a top-level import or export is treated as a module, with its own scope — nothing it declares leaks into the global scope, unlike a plain script file.
export function add(a: number, b: number): number {
return a + b;
}
export interface Point {
x: number;
y: number;
}import { add, Point } from "./math";
const sum = add(2, 3);
const p: Point = { x: 1, y: 2 };namespace: an older, TypeScript-only alternative
namespace groups related code under a single global-ish name using dot notation — it predates ES modules being widely usable in the JavaScript ecosystem, and today mostly appears in older codebases or specific library-declaration scenarios.
namespace Validation {
export function isValid(input: string): boolean {
return input.length > 0;
}
}
Validation.isValid("hello"); // accessed via dot notation, not importWhy the official guidance favors modules
Modules are standard JavaScript (no TypeScript-specific runtime behavior involved), integrate cleanly with bundlers and tree-shaking, and are what the entire modern JavaScript/TypeScript ecosystem is built around — this is precisely why the TypeScript documentation itself says to prefer modules to namespaces for ordinary application code, reserving namespace for the narrow cases (like organizing global ambient declaration files) where it genuinely still fits.