- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
TypeScript Namespace
In TypeScript, a namespace is a way to group related code under a single name, providing a logical structure for your application. Namespaces help organize large codebases by avoiding "global scope pollution"—a situation where too many variables and functions sit in the global space, increasing the risk of name conflicts. They are particularly useful when working with older JavaScript code or libraries where modern ES modules might not be available.
What is a Namespace?
Think of a namespace as a container or a "named folder" for your code. In a large project, you might have two different functions named Validate(). Without a namespace, these would clash. By placing them in namespaces like UserValidation and ProductValidation, you can keep them separate and organized. Namespaces can encapsulate variables, functions, interfaces, and classes, keeping the internal implementation hidden while only exposing what is necessary.
Creating a Namespace
To create a namespace in TypeScript, you use the namespace keyword, followed by the name of the namespace. Any code you want to be accessible from outside the namespace must be prefixed with the export keyword.
Example: Basic Namespace
namespace MathUtils {
// This constant is private to the namespace
const PI = 3.14;
export function add(x: number, y: number): number {
return x + y;
}
export function subtract(x: number, y: number): number {
return x - y;
}
}
- In this example, we have created a namespace called
MathUtils. - The
exportkeyword makesaddandsubtractaccessible to the rest of your application. - Notice that variables without
export(likePI) are "private" and can only be used insideMathUtils.
export keyword. If you don't export a function or class within a namespace, it will be invisible when you try to call it from outside, resulting in a "Property does not exist" error.
Example: Using a Namespace
let sum = MathUtils.add(10, 5);
console.log(sum); // Output: 15
- To access members of a namespace, we use the "dot notation" (
NamespaceName.MemberName).
Nested Namespaces
Namespaces can be nested within one another, allowing you to create a deep, hierarchical structure. This is great for very large libraries where you want to categorize code further (e.g., App.UI.Buttons).
Example: Nested Namespace
namespace Geometry {
export namespace Shapes {
export class Circle {
constructor(public radius: number) {}
area(): number {
return Math.PI * this.radius ** 2;
}
}
export class Square {
constructor(public side: number) {}
area(): number {
return this.side ** 2;
}
}
}
}
- In this example,
Shapesis a sub-category ofGeometry. Both the inner namespace and the classes must be exported to be usable.
Example: Using Nested Namespace
let circle = new Geometry.Shapes.Circle(5);
console.log(circle.area()); // Output: 78.5398...
let square = new Geometry.Shapes.Square(4);
console.log(square.area()); // Output: 16
Using Interfaces with Namespaces
Namespaces aren't just for logic; they are excellent for grouping Types and Interfaces. This ensures that your data models don't conflict with models from other parts of the app.
Example: Interface inside a Namespace
namespace AppData {
export interface User {
id: number;
name: string;
}
export class UserAccount implements User {
constructor(public id: number, public name: string) {}
}
}
- The
Userinterface is safely tucked away insideAppData. This allows you to have anotherUserinterface elsewhere (perhaps in aDatabasenamespace) without a collision.
Example: Using Interface from a Namespace
let myUser: AppData.User = { id: 1, name: "Jane Doe" };
let account = new AppData.UserAccount(2, "John Smith");
Aliasing a Namespace
If you have deeply nested namespaces or long names, typing the full path every time becomes tedious. TypeScript allows you to create an alias using the import keyword.
Example: Alias Namespace
import GShapes = Geometry.Shapes;
let myCircle = new GShapes.Circle(10);
console.log(myCircle.area());
- This is not a standard ES module import; it's a TypeScript-specific shortcut to simplify your code.
Namespaces vs Modules
This is the most important distinction to understand in modern TypeScript development.
- Namespaces: These are a TypeScript-specific way to organize code. They are usually compiled into a single JavaScript file using the
--outFileflag. They rely on the global scope to function. - Modules: (Recommended) Modules use
importandexportstatements. They are the standard in modern JavaScript (ES6) and work perfectly with bundlers like Webpack or Vite.
Summary
- Namespaces provide a way to group related code and prevent global scope pollution.
- Always use the export keyword to make namespace members available outside the block.
- Nesting allows for complex organizational structures, but should be used sparingly.
- Aliases help keep your code clean when dealing with long namespace paths.
- While still supported, Modules are generally preferred over Namespaces for modern TypeScript development.
By using namespaces effectively, you can build modular, maintainable, and conflict-free TypeScript applications, especially when dealing with architectural patterns that don't rely on modern bundlers.