Prerequisites
- Understanding of TypeScript modules and basic syntax 📝
- Knowledge of interfaces, classes, and functions ⚡
- Familiarity with JavaScript object structures 💻
What you'll learn
- Master namespace syntax and declaration patterns 🎯
- Create organized code hierarchies with logical grouping 🏗️
- Implement namespace merging and advanced features 🐛
- Build maintainable codebases with clean encapsulation ✨
🎯 Introduction
Welcome to the corporate headquarters of TypeScript code organization! 🏢 If modules were like separate office buildings each with their own address, then namespaces are like having different departments within the same building - accounting, marketing, engineering - all under one roof but clearly separated and organized!
Namespaces provide a way to organize code into logical groups within a single module. While modern TypeScript development primarily uses ES6 modules, namespaces still serve important purposes for organizing related functionality, creating libraries, and maintaining large codebases. They offer a powerful mechanism for creating hierarchical structures and avoiding naming conflicts.
By the end of this tutorial, you’ll be a namespace expert, capable of creating well-organized, maintainable code structures that make large applications easy to navigate and understand. Let’s explore the art of hierarchical code organization! 🌟
📚 Understanding Namespaces
🤔 What Are Namespaces?
Namespaces are a way to organize code by grouping related functionality under a common identifier. They create a hierarchical structure that helps prevent naming conflicts and provides logical organization for large codebases.
// 🌟 Basic namespace declaration
namespace MyCompany {
export interface Employee {
id: number;
name: string;
department: string;
}
export class EmployeeManager {
private employees: Employee[] = [];
addEmployee(employee: Employee): void {
this.employees.push(employee);
}
getEmployee(id: number): Employee | undefined {
return this.employees.find(emp => emp.id === id);
}
}
export function validateEmployee(employee: Employee): boolean {
return employee.id > 0 && employee.name.length > 0;
}
// Internal (non-exported) functionality
const COMPANY_NAME = 'My Company Inc.';
function generateEmployeeId(): number {
return Math.floor(Math.random() * 10000);
}
}
// ✨ Using namespace members
const employee: MyCompany.Employee = {
id: 1,
name: 'John Doe',
department: 'Engineering'
};
const manager = new MyCompany.EmployeeManager();
manager.addEmployee(employee);
const isValid = MyCompany.validateEmployee(employee);
// 🎯 Namespace vs Module comparison
// Namespace (internal organization)
namespace Utils {
export namespace String {
export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
export function truncate(str: string, length: number): string {
return str.length > length ? str.slice(0, length) + '...' : str;
}
}
export namespace Number {
export function round(num: number, decimals: number): number {
return Number(num.toFixed(decimals));
}
export function isEven(num: number): boolean {
return num % 2 === 0;
}
}
}
// Usage: Clear hierarchical access
const title = Utils.String.capitalize('hello world');
const shortText = Utils.String.truncate('This is a long text', 10);
const rounded = Utils.Number.round(3.14159, 2);
// Module (external organization)
// Would be in separate files:
// string-utils.ts: export function capitalize(str: string): string { ... }
// number-utils.ts: export function round(num: number, decimals: number): number { ... }
// index.ts: export * from './string-utils'; export * from './number-utils';
// 🏗️ Advanced namespace features
namespace AdvancedExample {
// 📊 Namespace can contain various types of declarations
export interface Config {
apiUrl: string;
timeout: number;
}
export type Status = 'pending' | 'success' | 'error';
export enum Priority {
LOW = 1,
MEDIUM = 2,
HIGH = 3,
CRITICAL = 4
}
export class Task {
constructor(
public id: string,
public title: string,
public priority: Priority = Priority.MEDIUM
) {}
getStatusMessage(): string {
return `Task ${this.id}: ${this.title} (Priority: ${Priority[this.priority]})`;
}
}
export namespace Validators {
export function validateConfig(config: Config): boolean {
return config.apiUrl.length > 0 && config.timeout > 0;
}
export function validateTask(task: Task): boolean {
return task.id.length > 0 && task.title.length > 0;
}
}
// 🔧 Internal utilities (not exported)
const DEFAULT_TIMEOUT = 5000;
function logDebug(message: string): void {
if (process.env.NODE_ENV === 'development') {
console.log(`[DEBUG] ${message}`);
}
}
// 📦 Factory functions
export function createTask(title: string, priority?: Priority): Task {
const id = generateTaskId();
logDebug(`Creating task with ID: ${id}`);
return new Task(id, title, priority);
}
export function createConfig(apiUrl: string, timeout?: number): Config {
return {
apiUrl,
timeout: timeout || DEFAULT_TIMEOUT
};
}
function generateTaskId(): string {
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}
// 🎮 Let's create a comprehensive namespace management system
console.log('🏢 Namespace Organization Examples');
// 🏗️ Namespace analyzer and organizer
namespace NamespaceAnalyzer {
// 📊 Track namespace statistics
export interface NamespaceStats {
name: string;
memberCount: number;
exportedMembers: number;
nestedNamespaces: number;
interfaces: number;
classes: number;
functions: number;
types: number;
enums: number;
}
export interface NamespaceStructure {
name: string;
path: string[];
members: NamespaceMember[];
children: NamespaceStructure[];
parent?: NamespaceStructure;
}
export interface NamespaceMember {
name: string;
type: 'interface' | 'class' | 'function' | 'type' | 'enum' | 'const' | 'namespace';
isExported: boolean;
signature?: string;
dependencies: string[];
}
// 📈 Namespace registry
const namespaceRegistry = new Map<string, NamespaceStructure>();
const memberUsage = new Map<string, number>();
// 🔍 Analyze namespace structure
export function analyzeNamespace(namespaceName: string): NamespaceStats {
console.log(`🔍 Analyzing namespace: ${namespaceName}`);
// 🎯 Simulate namespace introspection
const structure = getNamespaceStructure(namespaceName);
const stats: NamespaceStats = {
name: namespaceName,
memberCount: structure.members.length,
exportedMembers: structure.members.filter(m => m.isExported).length,
nestedNamespaces: structure.children.length,
interfaces: structure.members.filter(m => m.type === 'interface').length,
classes: structure.members.filter(m => m.type === 'class').length,
functions: structure.members.filter(m => m.type === 'function').length,
types: structure.members.filter(m => m.type === 'type').length,
enums: structure.members.filter(m => m.type === 'enum').length
};
console.log(`📊 Analysis complete:`, stats);
return stats;
}
// 🗂️ Get namespace structure
function getNamespaceStructure(namespaceName: string): NamespaceStructure {
// 🎯 Simulate namespace structure discovery
const structure: NamespaceStructure = {
name: namespaceName,
path: [namespaceName],
members: [
{
name: 'User',
type: 'interface',
isExported: true,
signature: 'interface User { id: string; name: string; }',
dependencies: []
},
{
name: 'UserService',
type: 'class',
isExported: true,
signature: 'class UserService { ... }',
dependencies: ['User']
},
{
name: 'validateUser',
type: 'function',
isExported: true,
signature: 'function validateUser(user: User): boolean',
dependencies: ['User']
},
{
name: 'INTERNAL_CONFIG',
type: 'const',
isExported: false,
signature: 'const INTERNAL_CONFIG = { ... }',
dependencies: []
}
],
children: []
};
return structure;
}
// 📊 Generate namespace report
export function generateNamespaceReport(namespaceName: string): {
structure: NamespaceStructure;
stats: NamespaceStats;
recommendations: string[];
complexity: 'low' | 'medium' | 'high';
} {
console.log(`📊 Generating report for namespace: ${namespaceName}`);
const structure = getNamespaceStructure(namespaceName);
const stats = analyzeNamespace(namespaceName);
const recommendations: string[] = [];
// 🎯 Analyze complexity
let complexity: 'low' | 'medium' | 'high' = 'low';
if (stats.memberCount > 20) {
complexity = 'high';
recommendations.push('Consider splitting large namespace into smaller ones');
} else if (stats.memberCount > 10) {
complexity = 'medium';
recommendations.push('Monitor namespace size for maintainability');
}
// 💡 Export recommendations
const exportRatio = stats.exportedMembers / stats.memberCount;
if (exportRatio < 0.3) {
recommendations.push('Low export ratio - consider if all members are needed');
} else if (exportRatio > 0.8) {
recommendations.push('High export ratio - ensure internal encapsulation');
}
// 🏗️ Structure recommendations
if (stats.nestedNamespaces === 0 && stats.memberCount > 15) {
recommendations.push('Consider using nested namespaces for better organization');
}
if (stats.interfaces > 10) {
recommendations.push('Consider creating a dedicated types namespace');
}
return {
structure,
stats,
recommendations,
complexity
};
}
// 🔧 Optimize namespace structure
export function optimizeNamespaceStructure(
namespaceName: string
): {
originalStructure: NamespaceStructure;
optimizedStructure: NamespaceStructure;
changes: string[];
} {
console.log(`🔧 Optimizing namespace structure: ${namespaceName}`);
const originalStructure = getNamespaceStructure(namespaceName);
const optimizedStructure = { ...originalStructure };
const changes: string[] = [];
// 📂 Group related members
const groupedMembers = groupMembersByType(originalStructure.members);
// 🏗️ Create nested namespaces for groups
if (groupedMembers.interfaces.length > 3) {
optimizedStructure.children.push({
name: 'Types',
path: [...originalStructure.path, 'Types'],
members: groupedMembers.interfaces,
children: []
});
changes.push('Created Types namespace for interfaces');
}
if (groupedMembers.functions.length > 5) {
optimizedStructure.children.push({
name: 'Utils',
path: [...originalStructure.path, 'Utils'],
members: groupedMembers.functions,
children: []
});
changes.push('Created Utils namespace for utility functions');
}
// 🧹 Remove grouped members from main namespace
optimizedStructure.members = originalStructure.members.filter(member =>
!groupedMembers.interfaces.includes(member) &&
!groupedMembers.functions.includes(member)
);
console.log(`✅ Optimization complete with ${changes.length} changes`);
return {
originalStructure,
optimizedStructure,
changes
};
}
// 📂 Group members by type
function groupMembersByType(members: NamespaceMember[]): {
interfaces: NamespaceMember[];
classes: NamespaceMember[];
functions: NamespaceMember[];
types: NamespaceMember[];
enums: NamespaceMember[];
constants: NamespaceMember[];
} {
return {
interfaces: members.filter(m => m.type === 'interface'),
classes: members.filter(m => m.type === 'class'),
functions: members.filter(m => m.type === 'function'),
types: members.filter(m => m.type === 'type'),
enums: members.filter(m => m.type === 'enum'),
constants: members.filter(m => m.type === 'const')
};
}
// 📊 Track member usage
export function trackMemberUsage(memberPath: string): void {
const currentUsage = memberUsage.get(memberPath) || 0;
memberUsage.set(memberPath, currentUsage + 1);
}
// 🔍 Find unused members
export function findUnusedMembers(namespaceName: string): NamespaceMember[] {
const structure = getNamespaceStructure(namespaceName);
return structure.members.filter(member => {
const memberPath = `${namespaceName}.${member.name}`;
const usage = memberUsage.get(memberPath) || 0;
return usage === 0 && member.isExported;
});
}
// 📈 Generate usage statistics
export function generateUsageStatistics(): {
totalMembers: number;
usedMembers: number;
mostUsedMembers: Array<{ path: string; usage: number }>;
unusedMembers: string[];
} {
const totalMembers = memberUsage.size;
const usedMembers = Array.from(memberUsage.values()).filter(usage => usage > 0).length;
const sortedUsage = Array.from(memberUsage.entries())
.sort(([,a], [,b]) => b - a)
.slice(0, 10);
const mostUsedMembers = sortedUsage.map(([path, usage]) => ({ path, usage }));
const unusedMembers = Array.from(memberUsage.entries())
.filter(([, usage]) => usage === 0)
.map(([path]) => path);
return {
totalMembers,
usedMembers,
mostUsedMembers,
unusedMembers
};
}
}
// 🎮 Usage examples
const namespaceDemo = (): void => {
// 🔍 Analyze namespace
const stats = NamespaceAnalyzer.analyzeNamespace('MyCompany');
console.log('📊 Namespace Stats:', stats);
// 📊 Generate comprehensive report
const report = NamespaceAnalyzer.generateNamespaceReport('MyCompany');
console.log('📋 Namespace Report:', report);
// 🔧 Optimize structure
const optimization = NamespaceAnalyzer.optimizeNamespaceStructure('MyCompany');
console.log('🔧 Optimization Results:', optimization);
// 📈 Track usage
NamespaceAnalyzer.trackMemberUsage('MyCompany.Employee');
NamespaceAnalyzer.trackMemberUsage('MyCompany.EmployeeManager');
const usageStats = NamespaceAnalyzer.generateUsageStatistics();
console.log('📈 Usage Statistics:', usageStats);
};
// 🎯 Advanced namespace patterns
namespace AdvancedPatterns {
// 🌟 Pattern 1: Plugin Architecture
export namespace PluginSystem {
export interface Plugin {
name: string;
version: string;
initialize(): void;
execute(context: PluginContext): PluginResult;
cleanup(): void;
}
export interface PluginContext {
data: Record<string, any>;
config: Record<string, any>;
utilities: PluginUtilities;
}
export interface PluginResult {
success: boolean;
data?: any;
errors?: string[];
}
export interface PluginUtilities {
log: (message: string) => void;
cache: {
get: (key: string) => any;
set: (key: string, value: any) => void;
};
}
const registeredPlugins = new Map<string, Plugin>();
export function registerPlugin(plugin: Plugin): void {
console.log(`🔌 Registering plugin: ${plugin.name}`);
registeredPlugins.set(plugin.name, plugin);
plugin.initialize();
}
export function executePlugin(
pluginName: string,
context: PluginContext
): PluginResult {
const plugin = registeredPlugins.get(pluginName);
if (!plugin) {
return {
success: false,
errors: [`Plugin not found: ${pluginName}`]
};
}
console.log(`⚡ Executing plugin: ${pluginName}`);
return plugin.execute(context);
}
export function listPlugins(): Plugin[] {
return Array.from(registeredPlugins.values());
}
}
// 🌟 Pattern 2: Event System
export namespace EventSystem {
export interface Event<T = any> {
type: string;
data: T;
timestamp: number;
source?: string;
}
export interface EventHandler<T = any> {
(event: Event<T>): void | Promise<void>;
}
export interface EventSubscription {
unsubscribe(): void;
}
const eventListeners = new Map<string, Set<EventHandler>>();
const eventHistory: Event[] = [];
export function subscribe<T>(
eventType: string,
handler: EventHandler<T>
): EventSubscription {
console.log(`📡 Subscribing to event: ${eventType}`);
if (!eventListeners.has(eventType)) {
eventListeners.set(eventType, new Set());
}
eventListeners.get(eventType)!.add(handler);
return {
unsubscribe: () => {
console.log(`📡 Unsubscribing from event: ${eventType}`);
eventListeners.get(eventType)?.delete(handler);
}
};
}
export async function emit<T>(event: Event<T>): Promise<void> {
console.log(`📢 Emitting event: ${event.type}`);
// 📚 Store in history
eventHistory.push(event);
// 🔄 Notify all listeners
const listeners = eventListeners.get(event.type);
if (listeners) {
const promises = Array.from(listeners).map(handler =>
Promise.resolve(handler(event))
);
await Promise.all(promises);
}
}
export function createEvent<T>(
type: string,
data: T,
source?: string
): Event<T> {
return {
type,
data,
timestamp: Date.now(),
source
};
}
export function getEventHistory(
eventType?: string,
limit?: number
): Event[] {
let events = eventHistory;
if (eventType) {
events = events.filter(event => event.type === eventType);
}
if (limit) {
events = events.slice(-limit);
}
return events;
}
}
// 🌟 Pattern 3: State Management
export namespace StateManager {
export interface State {
[key: string]: any;
}
export interface StateChange<T = any> {
path: string;
oldValue: T;
newValue: T;
timestamp: number;
}
export interface StateSubscriber {
(change: StateChange): void;
}
let currentState: State = {};
const subscribers = new Set<StateSubscriber>();
const stateHistory: StateChange[] = [];
export function getState(): State {
return { ...currentState };
}
export function setState(path: string, value: any): void {
const oldValue = getValueAtPath(currentState, path);
if (oldValue !== value) {
console.log(`🔄 State change: ${path}`);
setValueAtPath(currentState, path, value);
const change: StateChange = {
path,
oldValue,
newValue: value,
timestamp: Date.now()
};
stateHistory.push(change);
notifySubscribers(change);
}
}
export function subscribe(subscriber: StateSubscriber): () => void {
console.log(`📡 Subscribing to state changes`);
subscribers.add(subscriber);
return () => {
console.log(`📡 Unsubscribing from state changes`);
subscribers.delete(subscriber);
};
}
export function getStateHistory(path?: string): StateChange[] {
if (path) {
return stateHistory.filter(change => change.path === path);
}
return [...stateHistory];
}
function getValueAtPath(obj: any, path: string): any {
return path.split('.').reduce((current, key) => current?.[key], obj);
}
function setValueAtPath(obj: any, path: string, value: any): void {
const keys = path.split('.');
const lastKey = keys.pop()!;
const target = keys.reduce((current, key) => {
if (!(key in current)) {
current[key] = {};
}
return current[key];
}, obj);
target[lastKey] = value;
}
function notifySubscribers(change: StateChange): void {
subscribers.forEach(subscriber => {
try {
subscriber(change);
} catch (error) {
console.error('State subscriber error:', error);
}
});
}
}
// 🌟 Pattern 4: Configuration Management
export namespace ConfigManager {
export interface ConfigSchema {
[key: string]: {
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
required?: boolean;
default?: any;
validator?: (value: any) => boolean;
description?: string;
};
}
export interface ConfigValue {
value: any;
source: 'default' | 'environment' | 'file' | 'runtime';
validated: boolean;
}
const configSchemas = new Map<string, ConfigSchema>();
const configValues = new Map<string, ConfigValue>();
export function defineSchema(name: string, schema: ConfigSchema): void {
console.log(`📋 Defining config schema: ${name}`);
configSchemas.set(name, schema);
// 🎯 Apply default values
Object.entries(schema).forEach(([key, config]) => {
if (config.default !== undefined) {
setConfig(`${name}.${key}`, config.default, 'default');
}
});
}
export function setConfig(
path: string,
value: any,
source: ConfigValue['source'] = 'runtime'
): boolean {
console.log(`⚙️ Setting config: ${path} = ${value}`);
const isValid = validateConfig(path, value);
configValues.set(path, {
value,
source,
validated: isValid
});
return isValid;
}
export function getConfig<T = any>(path: string): T | undefined {
const configValue = configValues.get(path);
return configValue?.value;
}
export function validateConfig(path: string, value: any): boolean {
const [schemaName, configKey] = path.split('.');
const schema = configSchemas.get(schemaName);
if (!schema || !schema[configKey]) {
return false;
}
const config = schema[configKey];
// 🎯 Type validation
if (!validateType(value, config.type)) {
return false;
}
// 🔧 Custom validation
if (config.validator && !config.validator(value)) {
return false;
}
return true;
}
function validateType(value: any, expectedType: string): boolean {
switch (expectedType) {
case 'string':
return typeof value === 'string';
case 'number':
return typeof value === 'number' && !isNaN(value);
case 'boolean':
return typeof value === 'boolean';
case 'object':
return typeof value === 'object' && value !== null && !Array.isArray(value);
case 'array':
return Array.isArray(value);
default:
return false;
}
}
export function getAllConfigs(): Record<string, ConfigValue> {
return Object.fromEntries(configValues);
}
export function validateAllConfigs(): {
valid: string[];
invalid: string[];
} {
const valid: string[] = [];
const invalid: string[] = [];
configValues.forEach((configValue, path) => {
if (configValue.validated) {
valid.push(path);
} else {
invalid.push(path);
}
});
return { valid, invalid };
}
}
}
// 🎮 Advanced usage examples
const advancedNamespaceDemo = (): void => {
// 🔌 Plugin system demo
const examplePlugin: AdvancedPatterns.PluginSystem.Plugin = {
name: 'ExamplePlugin',
version: '1.0.0',
initialize: () => console.log('🔌 Plugin initialized'),
execute: (context) => {
console.log('⚡ Plugin executing with context:', context.data);
return { success: true, data: 'Plugin result' };
},
cleanup: () => console.log('🧹 Plugin cleaned up')
};
AdvancedPatterns.PluginSystem.registerPlugin(examplePlugin);
const pluginResult = AdvancedPatterns.PluginSystem.executePlugin('ExamplePlugin', {
data: { input: 'test' },
config: {},
utilities: {
log: console.log,
cache: {
get: (key) => `cached_${key}`,
set: (key, value) => console.log(`Cache set: ${key} = ${value}`)
}
}
});
// 📡 Event system demo
const subscription = AdvancedPatterns.EventSystem.subscribe('user.login', (event) => {
console.log(`👤 User logged in:`, event.data);
});
AdvancedPatterns.EventSystem.emit(
AdvancedPatterns.EventSystem.createEvent('user.login', { userId: '123', name: 'John' })
);
// 🔄 State management demo
const stateUnsubscribe = AdvancedPatterns.StateManager.subscribe((change) => {
console.log(`📊 State changed:`, change);
});
AdvancedPatterns.StateManager.setState('user.name', 'Alice');
AdvancedPatterns.StateManager.setState('app.theme', 'dark');
// ⚙️ Configuration demo
AdvancedPatterns.ConfigManager.defineSchema('app', {
apiUrl: {
type: 'string',
required: true,
description: 'API base URL'
},
timeout: {
type: 'number',
default: 5000,
validator: (value) => value > 0,
description: 'Request timeout in milliseconds'
},
debug: {
type: 'boolean',
default: false,
description: 'Enable debug mode'
}
});
AdvancedPatterns.ConfigManager.setConfig('app.apiUrl', 'https://api.example.com');
AdvancedPatterns.ConfigManager.setConfig('app.debug', true);
const apiUrl = AdvancedPatterns.ConfigManager.getConfig<string>('app.apiUrl');
console.log('🔧 API URL:', apiUrl);
};
// 🎯 Execute demonstrations
namespaceDemo();
advancedNamespaceDemo();
💡 Common Namespace Patterns
Let’s explore the most effective patterns for organizing code with namespaces:
// 🌟 Pattern 1: Domain-Driven Organization
// Organize namespaces around business domains
namespace ECommerce {
// 🛍️ Product domain
export namespace Products {
export interface Product {
id: string;
name: string;
price: number;
category: Category;
inventory: InventoryInfo;
}
export interface Category {
id: string;
name: string;
parent?: Category;
}
export interface InventoryInfo {
inStock: number;
reserved: number;
available: number;
}
export class ProductService {
async getProduct(id: string): Promise<Product | null> {
// Implementation
return null;
}
async updateInventory(
productId: string,
quantity: number
): Promise<void> {
// Implementation
}
}
export namespace Validators {
export function validateProduct(product: Product): boolean {
return product.id.length > 0 &&
product.price > 0 &&
product.inventory.available >= 0;
}
export function validateCategory(category: Category): boolean {
return category.id.length > 0 && category.name.length > 0;
}
}
}
// 👤 User domain
export namespace Users {
export interface User {
id: string;
email: string;
profile: UserProfile;
preferences: UserPreferences;
}
export interface UserProfile {
firstName: string;
lastName: string;
avatar?: string;
addresses: Address[];
}
export interface Address {
id: string;
street: string;
city: string;
postalCode: string;
country: string;
isDefault: boolean;
}
export interface UserPreferences {
currency: string;
language: string;
emailNotifications: boolean;
smsNotifications: boolean;
}
export class UserService {
async createUser(userData: CreateUserData): Promise<User> {
// Implementation
return {} as User;
}
async updateProfile(
userId: string,
profile: Partial<UserProfile>
): Promise<void> {
// Implementation
}
}
export type CreateUserData = Omit<User, 'id'>;
}
// 🛒 Order domain
export namespace Orders {
export interface Order {
id: string;
userId: string;
items: OrderItem[];
shipping: ShippingInfo;
payment: PaymentInfo;
status: OrderStatus;
totals: OrderTotals;
}
export interface OrderItem {
productId: string;
quantity: number;
unitPrice: number;
totalPrice: number;
}
export interface ShippingInfo {
address: Users.Address;
method: ShippingMethod;
trackingNumber?: string;
}
export interface PaymentInfo {
method: PaymentMethod;
transactionId: string;
amount: number;
}
export type OrderStatus =
| 'pending'
| 'confirmed'
| 'processing'
| 'shipped'
| 'delivered'
| 'cancelled';
export type ShippingMethod = 'standard' | 'express' | 'overnight';
export type PaymentMethod = 'credit_card' | 'paypal' | 'bank_transfer';
export interface OrderTotals {
subtotal: number;
tax: number;
shipping: number;
discount: number;
total: number;
}
export class OrderService {
async createOrder(orderData: CreateOrderData): Promise<Order> {
// Implementation
return {} as Order;
}
async updateOrderStatus(
orderId: string,
status: OrderStatus
): Promise<void> {
// Implementation
}
}
export type CreateOrderData = Omit<Order, 'id' | 'status'>;
}
// 💳 Payment domain
export namespace Payments {
export interface PaymentProcessor {
processPayment(request: PaymentRequest): Promise<PaymentResult>;
refundPayment(transactionId: string, amount: number): Promise<RefundResult>;
}
export interface PaymentRequest {
amount: number;
currency: string;
method: Orders.PaymentMethod;
customerInfo: PaymentCustomerInfo;
metadata?: Record<string, any>;
}
export interface PaymentCustomerInfo {
id: string;
email: string;
name: string;
}
export interface PaymentResult {
success: boolean;
transactionId: string;
amount: number;
fees: number;
error?: PaymentError;
}
export interface RefundResult {
success: boolean;
refundId: string;
amount: number;
error?: PaymentError;
}
export interface PaymentError {
code: string;
message: string;
details?: Record<string, any>;
}
export class StripePaymentProcessor implements PaymentProcessor {
async processPayment(request: PaymentRequest): Promise<PaymentResult> {
// Stripe implementation
return {} as PaymentResult;
}
async refundPayment(
transactionId: string,
amount: number
): Promise<RefundResult> {
// Stripe refund implementation
return {} as RefundResult;
}
}
}
}
// 🌟 Pattern 2: Technical Layer Organization
// Organize by technical concerns and layers
namespace Application {
// 🗄️ Data layer
export namespace Data {
export interface Repository<T, K = string> {
findById(id: K): Promise<T | null>;
findAll(): Promise<T[]>;
create(entity: Omit<T, 'id'>): Promise<T>;
update(id: K, entity: Partial<T>): Promise<T>;
delete(id: K): Promise<void>;
}
export interface QueryBuilder<T> {
where(field: keyof T, value: any): QueryBuilder<T>;
orderBy(field: keyof T, direction: 'asc' | 'desc'): QueryBuilder<T>;
limit(count: number): QueryBuilder<T>;
offset(count: number): QueryBuilder<T>;
execute(): Promise<T[]>;
}
export class DatabaseConnection {
private isConnected = false;
async connect(connectionString: string): Promise<void> {
console.log('🔌 Connecting to database...');
this.isConnected = true;
}
async disconnect(): Promise<void> {
console.log('🔌 Disconnecting from database...');
this.isConnected = false;
}
isHealthy(): boolean {
return this.isConnected;
}
}
export abstract class BaseRepository<T, K = string> implements Repository<T, K> {
protected abstract tableName: string;
async findById(id: K): Promise<T | null> {
console.log(`🔍 Finding ${this.tableName} by ID: ${id}`);
// Implementation
return null;
}
async findAll(): Promise<T[]> {
console.log(`📋 Finding all ${this.tableName}`);
// Implementation
return [];
}
async create(entity: Omit<T, 'id'>): Promise<T> {
console.log(`➕ Creating ${this.tableName}`);
// Implementation
return entity as T;
}
async update(id: K, entity: Partial<T>): Promise<T> {
console.log(`✏️ Updating ${this.tableName} ${id}`);
// Implementation
return entity as T;
}
async delete(id: K): Promise<void> {
console.log(`🗑️ Deleting ${this.tableName} ${id}`);
// Implementation
}
}
}
// 🏗️ Service layer
export namespace Services {
export interface ServiceContext {
userId?: string;
requestId: string;
timestamp: number;
metadata: Record<string, any>;
}
export interface ServiceResult<T> {
success: boolean;
data?: T;
error?: ServiceError;
}
export interface ServiceError {
code: string;
message: string;
details?: any;
}
export abstract class BaseService {
protected context?: ServiceContext;
setContext(context: ServiceContext): void {
this.context = context;
}
protected createResult<T>(data: T): ServiceResult<T> {
return { success: true, data };
}
protected createError(
code: string,
message: string,
details?: any
): ServiceResult<never> {
return {
success: false,
error: { code, message, details }
};
}
protected logOperation(operation: string, details?: any): void {
console.log(`🔧 Service operation: ${operation}`, {
service: this.constructor.name,
context: this.context?.requestId,
details
});
}
}
export class ValidationService extends BaseService {
validate<T>(data: T, rules: ValidationRules<T>): ServiceResult<T> {
this.logOperation('validate', { rules });
for (const [field, rule] of Object.entries(rules)) {
const value = (data as any)[field];
if (!this.validateField(value, rule as ValidationRule)) {
return this.createError(
'VALIDATION_FAILED',
`Validation failed for field: ${field}`
);
}
}
return this.createResult(data);
}
private validateField(value: any, rule: ValidationRule): boolean {
if (rule.required && (value === undefined || value === null)) {
return false;
}
if (rule.type && typeof value !== rule.type) {
return false;
}
if (rule.validator && !rule.validator(value)) {
return false;
}
return true;
}
}
export interface ValidationRule {
required?: boolean;
type?: string;
validator?: (value: any) => boolean;
}
export type ValidationRules<T> = {
[K in keyof T]?: ValidationRule;
};
}
// 🌐 Web layer
export namespace Web {
export interface Request {
method: string;
url: string;
headers: Record<string, string>;
body?: any;
params: Record<string, string>;
query: Record<string, string>;
}
export interface Response {
status: number;
headers: Record<string, string>;
body?: any;
}
export interface Middleware {
(request: Request, response: Response, next: () => void): void | Promise<void>;
}
export interface Controller {
handle(request: Request): Promise<Response>;
}
export abstract class BaseController implements Controller {
abstract handle(request: Request): Promise<Response>;
protected createResponse(
status: number,
body?: any,
headers?: Record<string, string>
): Response {
return {
status,
body,
headers: headers || {}
};
}
protected ok(data?: any): Response {
return this.createResponse(200, data);
}
protected created(data?: any): Response {
return this.createResponse(201, data);
}
protected badRequest(error?: string): Response {
return this.createResponse(400, { error });
}
protected notFound(error?: string): Response {
return this.createResponse(404, { error });
}
protected serverError(error?: string): Response {
return this.createResponse(500, { error });
}
}
export class Router {
private routes = new Map<string, Controller>();
register(path: string, controller: Controller): void {
console.log(`🛣️ Registering route: ${path}`);
this.routes.set(path, controller);
}
async route(request: Request): Promise<Response> {
const controller = this.routes.get(request.url);
if (!controller) {
return {
status: 404,
headers: {},
body: { error: 'Route not found' }
};
}
return await controller.handle(request);
}
}
}
// 🔧 Utilities layer
export namespace Utils {
export namespace Logger {
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3
}
export interface LogEntry {
level: LogLevel;
message: string;
timestamp: number;
context?: any;
}
let currentLogLevel = LogLevel.INFO;
export function setLogLevel(level: LogLevel): void {
currentLogLevel = level;
}
export function debug(message: string, context?: any): void {
log(LogLevel.DEBUG, message, context);
}
export function info(message: string, context?: any): void {
log(LogLevel.INFO, message, context);
}
export function warn(message: string, context?: any): void {
log(LogLevel.WARN, message, context);
}
export function error(message: string, context?: any): void {
log(LogLevel.ERROR, message, context);
}
function log(level: LogLevel, message: string, context?: any): void {
if (level >= currentLogLevel) {
const entry: LogEntry = {
level,
message,
timestamp: Date.now(),
context
};
console.log(`[${LogLevel[level]}] ${message}`, context || '');
}
}
}
export namespace Cache {
const cache = new Map<string, CacheEntry>();
interface CacheEntry {
value: any;
expiry: number;
}
export function set(
key: string,
value: any,
ttlSeconds: number = 300
): void {
const expiry = Date.now() + (ttlSeconds * 1000);
cache.set(key, { value, expiry });
}
export function get<T = any>(key: string): T | null {
const entry = cache.get(key);
if (!entry) {
return null;
}
if (Date.now() > entry.expiry) {
cache.delete(key);
return null;
}
return entry.value;
}
export function has(key: string): boolean {
return get(key) !== null;
}
export function delete(key: string): boolean {
return cache.delete(key);
}
export function clear(): void {
cache.clear();
}
export function size(): number {
// Clean expired entries first
const now = Date.now();
for (const [key, entry] of cache.entries()) {
if (now > entry.expiry) {
cache.delete(key);
}
}
return cache.size;
}
}
export namespace Crypto {
export function generateId(length: number = 8): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
export function hash(input: string): string {
// Simple hash function (use proper crypto in production)
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash).toString(16);
}
}
}
}
// Usage examples demonstrating the organized structure
const layeredArchitectureDemo = (): void => {
// 🗄️ Data layer usage
class UserRepository extends Application.Data.BaseRepository<ECommerce.Users.User> {
protected tableName = 'users';
}
// 🏗️ Service layer usage
class UserService extends Application.Services.BaseService {
constructor(private userRepo: UserRepository) {
super();
}
async createUser(userData: ECommerce.Users.CreateUserData): Promise<Application.Services.ServiceResult<ECommerce.Users.User>> {
this.logOperation('createUser');
try {
const user = await this.userRepo.create(userData);
return this.createResult(user);
} catch (error) {
return this.createError('USER_CREATION_FAILED', 'Failed to create user');
}
}
}
// 🌐 Web layer usage
class UserController extends Application.Web.BaseController {
constructor(private userService: UserService) {
super();
}
async handle(request: Application.Web.Request): Promise<Application.Web.Response> {
if (request.method === 'POST') {
const result = await this.userService.createUser(request.body);
if (result.success) {
return this.created(result.data);
} else {
return this.badRequest(result.error?.message);
}
}
return this.badRequest('Method not allowed');
}
}
// 🔧 Utilities usage
Application.Utils.Logger.setLogLevel(Application.Utils.Logger.LogLevel.DEBUG);
Application.Utils.Logger.info('Application starting...');
Application.Utils.Cache.set('user:123', { name: 'John' }, 60);
const cachedUser = Application.Utils.Cache.get('user:123');
const sessionId = Application.Utils.Crypto.generateId(16);
console.log('Generated session ID:', sessionId);
};
// Execute the demo
layeredArchitectureDemo();
🎉 Conclusion
Congratulations! You’ve mastered the fundamentals of TypeScript namespaces! 🏢
🎯 What You’ve Learned
- 🏗️ Namespace Syntax: Creating and organizing code with namespace declarations
- 📂 Hierarchical Organization: Building logical code structures with nested namespaces
- 🔧 Advanced Patterns: Sophisticated namespace patterns for different architectural needs
- 📊 Code Analysis: Tools and techniques for analyzing and optimizing namespace structures
- 🎯 Best Practices: Effective strategies for maintaining organized, scalable codebases
🚀 Key Benefits
- 🏗️ Better Organization: Clear, logical structure for large codebases
- 🔒 Encapsulation: Control over what gets exposed publicly vs. kept internal
- 📂 Hierarchical Structure: Natural grouping of related functionality
- 🚫 Naming Conflict Prevention: Isolated scope prevents name collisions
- 📚 Self-Documenting Code: Structure that clearly communicates intent and relationships
🔥 Best Practices Recap
- 🎯 Group by Purpose: Organize related functionality together logically
- 🔒 Control Exports: Only export what should be part of the public API
- 📂 Use Hierarchies: Leverage nested namespaces for complex domains
- 📊 Monitor Complexity: Keep individual namespaces focused and manageable
- 🔧 Consider Modern Alternatives: Evaluate when ES6 modules might be more appropriate
You’re now equipped to create well-organized, maintainable TypeScript codebases using namespaces effectively! Whether you’re building libraries, organizing large applications, or creating domain-specific APIs, namespaces provide powerful tools for code organization. 🌟
Happy coding, and may your code always be beautifully organized! 🏢✨