TypeScript Namespaces: The Original Module System
TypeScript namespaces bundle related code under a single global name, preventing name collisions. They are useful for older projects or UMD library types, but the footgun is using them in modern apps; prefer standard ES modules.
WHY IT EXISTS: Before ES modules became standard, JavaScript code running in a browser shared a single global scope. This led to "global namespace pollution," where different scripts could accidentally overwrite each other's variables. Namespaces were TypeScript's early solution to this problem, providing a way to group related code and avoid name clashes.
THE MENTAL MODEL: A namespace is like a labeled box for your code. You put related items—classes, interfaces, functions—inside the box. To use an item from outside, you have to refer to it by the box's label, like MyBox.MyItem. Anything you don't explicitly mark for external use stays hidden inside the box.
HOW IT WORKS: You define a namespace with the namespace keyword, followed by a name and curly braces, for example: namespace Validation { ... }. Inside this block, you can write any TypeScript code. To make a class, interface, or variable visible outside the namespace, you must prefix its declaration with the export keyword. Anything not exported remains private to the namespace, acting as an implementation detail.
WHEN TO USE IT: Namespaces are still relevant for structuring declaration files (.d.ts) for libraries that can be loaded via a <script> tag and expose a global variable (e.g., jQuery being available as $ or jQuery). They are also found in older TypeScript projects that were written before ES modules were widely adopted.
WHEN NOT TO USE IT: For any new application development, you should avoid using namespaces to structure your code. The modern JavaScript ecosystem is built around ES modules (import and export). Modules provide a much better system for declaring dependencies, enabling static analysis, and allowing tools like bundlers to perform tree-shaking to reduce code size.
ONE CANONICAL EXAMPLE: To group a set of string validators, you could create a Validation namespace. Inside, you might define and export a StringValidator interface and two classes, LettersOnlyValidator and ZipCodeValidator. A consumer of this namespace would then access the classes using dot notation, like const zipValidator = new Validation.ZipCodeValidator();, keeping the validator classes from polluting the global scope.
Read the original → typescriptlang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.