Master TypeScript module systems, namespaces, and enterprise-grade project organization. Learn ES modules, declaration files, ambient modules, and scalable architecture patterns.
TypeScript's module system is essential for building large, maintainable applications. Understanding modules, namespaces, and project organization enables you to structure code effectively, manage dependencies, and create reusable libraries.
Modern TypeScript primarily uses ES modules, but also supports CommonJS, AMD, and other module systems. You'll learn how to organize code across files, create declaration files for type safety, and implement patterns that scale from small projects to enterprise applications.
This lesson covers both the technical aspects of TypeScript's module system and the architectural patterns that make projects maintainable and scalable over time.
ES modules are the standard for modern TypeScript applications, providing static analysis benefits and tree-shaking capabilities.
Basic Import and Export:
1// math.ts - Named exports
2export function add(a: number, b: number): number {
3 return a + b;
4}
5
6export function multiply(a: number, b: number): number {
7 return a * b;
8}
9
10export const PI = 3.14159;
11
12export class Calculator {
13 add(a: number, b: number): number {
14 return add(a, b);
15 }
16}
17
18// Alternative named export syntax
19function subtract(a: number, b: number): number {
20 return a - b;
21}
22
23function divide(a: number, b: number): number {
24 if (b === 0) throw new Error("Division by zero");
25 return a / b;
26}
27
28export { subtract, divide };
29
30// utils.ts - Default export
31export default class Logger {
32 log(message: string): void {
33 console.log(`[${new Date().toISOString()}] ${message}`);
34 }
35}
36
37// app.ts - Import patterns
38import Logger from './utils'; // Default import
39import { add, multiply, PI } from './math'; // Named imports
40import { subtract as sub, divide } from './math'; // Aliased import
41import * as MathUtils from './math'; // Namespace import
42
43const logger = new Logger();
44logger.log("Application started");
45
46console.log(add(5, 3));
47console.log(sub(10, 4));
48console.log(PI);
49console.log(MathUtils.Calculator);Re-exports and Barrel Exports:
1// types/user.ts
2export interface User {
3 id: string;
4 name: string;
5 email: string;
6}
7
8export interface UserPreferences {
9 theme: "light" | "dark";
10 language: string;
11}
12
13// types/product.ts
14export interface Product {
15 id: string;
16 name: string;
17 price: number;
18}
19
20export interface ProductCategory {
21 id: string;
22 name: string;
23}
24
25// types/index.ts - Barrel export
26export * from './user';
27export * from './product';
28
29// Or selective re-exports
30export { User, UserPreferences } from './user';
31export { Product } from './product';
32
33// services/userService.ts
34import { User, UserPreferences } from '../types';
35
36export class UserService {
37 async getUser(id: string): Promise<User> {
38 // Implementation
39 return { id, name: "John", email: "[email protected]" };
40 }
41
42 async updatePreferences(userId: string, prefs: UserPreferences): Promise<void> {
43 // Implementation
44 }
45}
46
47// services/index.ts
48export { UserService } from './userService';
49export { ProductService } from './productService';
50
51// main.ts - Clean imports through barrel exports
52import { User, Product } from './types';
53import { UserService, ProductService } from './services';Dynamic Imports:
1// Conditional dynamic imports
2async function loadFeature(featureName: string): Promise<void> {
3 switch (featureName) {
4 case 'analytics':
5 const { AnalyticsModule } = await import('./features/analytics');
6 new AnalyticsModule().initialize();
7 break;
8 case 'chat':
9 const { ChatModule } = await import('./features/chat');
10 new ChatModule().connect();
11 break;
12 default:
13 console.log(`Unknown feature: ${featureName}`);
14 }
15}
16
17// Lazy loading with error handling
18async function loadUserDashboard(): Promise<void> {
19 try {
20 const [
21 { DashboardComponent },
22 { UserService },
23 { ChartLibrary }
24 ] = await Promise.all([
25 import('./components/Dashboard'),
26 import('./services/UserService'),
27 import('./lib/charts')
28 ]);
29
30 const userService = new UserService();
31 const dashboard = new DashboardComponent(userService);
32 dashboard.render();
33 } catch (error) {
34 console.error('Failed to load dashboard:', error);
35 }
36}
37
38// Feature detection and progressive enhancement
39const supportsWebGL = 'WebGLRenderingContext' in window;
40
41if (supportsWebGL) {
42 import('./renderers/webgl-renderer').then(({ WebGLRenderer }) => {
43 new WebGLRenderer().initialize();
44 });
45} else {
46 import('./renderers/canvas-renderer').then(({ CanvasRenderer }) => {
47 new CanvasRenderer().initialize();
48 });
49}Module Resolution and Path Mapping:
1// tsconfig.json - Path mapping configuration
2{
3 "compilerOptions": {
4 "baseUrl": "./src",
5 "paths": {
6 "@/*": ["*"],
7 "@/components/*": ["components/*"],
8 "@/services/*": ["services/*"],
9 "@/types/*": ["types/*"],
10 "@/utils/*": ["utils/*"]
11 }
12 }
13}
14
15// Using path aliases
16import { Button } from '@/components/Button';
17import { UserService } from '@/services/UserService';
18import { User } from '@/types/User';
19import { formatDate } from '@/utils/date';
20
21// Relative imports for local modules
22import { validateInput } from './validation';
23import { LocalConfig } from '../config';Side Effect Imports:
1// polyfills.ts
2import 'core-js/stable';
3import 'regenerator-runtime/runtime';
4
5// CSS imports (in frameworks that support it)
6import './styles/global.css';
7import './styles/components.scss';
8
9// Module with side effects
10import './monitoring/error-tracking';
11import './monitoring/performance';
12
13// Conditional polyfills
14if (!Array.prototype.includes) {
15 import('./polyfills/array-includes');
16}
17
18// Feature flag based imports
19if (process.env.NODE_ENV === 'development') {
20 import('./dev-tools/debugging').then(({ initDevTools }) => {
21 initDevTools();
22 });
23}Declaration files (.d.ts) provide type information for JavaScript libraries and enable TypeScript integration with external code.
Basic Declaration Files:
1// types/lodash.d.ts - External library declarations
2declare module 'lodash' {
3 interface LoDashStatic {
4 chunk<T>(array: T[], size?: number): T[][];
5 debounce<T extends (...args: any[]) => any>(
6 func: T,
7 wait?: number,
8 options?: { leading?: boolean; trailing?: boolean }
9 ): T;
10 merge<T, U>(object: T, source: U): T & U;
11 }
12
13 const _: LoDashStatic;
14 export = _;
15}
16
17// types/environment.d.ts - Ambient declarations
18declare global {
19 namespace NodeJS {
20 interface ProcessEnv {
21 NODE_ENV: 'development' | 'production' | 'test';
22 API_URL: string;
23 DATABASE_URL: string;
24 JWT_SECRET: string;
25 }
26 }
27
28 interface Window {
29 gtag: (command: string, ...args: any[]) => void;
30 dataLayer: any[];
31 grecaptcha: {
32 ready: (callback: () => void) => void;
33 execute: (siteKey: string, options: { action: string }) => Promise<string>;
34 };
35 }
36}
37
38// types/modules.d.ts - Module format declarations
39declare module '*.css' {
40 const content: { [className: string]: string };
41 export default content;
42}
43
44declare module '*.scss' {
45 const content: { [className: string]: string };
46 export default content;
47}
48
49declare module '*.png' {
50 const src: string;
51 export default src;
52}
53
54declare module '*.svg' {
55 import { ComponentType, SVGProps } from 'react';
56 const ReactComponent: ComponentType<SVGProps<SVGSVGElement>>;
57 export { ReactComponent };
58 const src: string;
59 export default src;
60}
61
62// Using the declarations
63import _ from 'lodash';
64import styles from './Component.module.css';
65import logo from './assets/logo.png';
66
67const chunkedArray = _.chunk([1, 2, 3, 4, 5], 2);
68const debouncedFn = _.debounce(() => console.log('Hello'), 300);
69
70console.log(process.env.NODE_ENV);
71window.gtag('config', 'GA_MEASUREMENT_ID');Creating Declaration Files for Libraries:
1// src/math-utils.ts - Your library
2export function fibonacci(n: number): number {
3 if (n <= 1) return n;
4 return fibonacci(n - 1) + fibonacci(n - 2);
5}
6
7export function isPrime(n: number): boolean {
8 if (n <= 1) return false;
9 for (let i = 2; i * i <= n; i++) {
10 if (n % i === 0) return false;
11 }
12 return true;
13}
14
15export class Matrix {
16 constructor(public rows: number, public cols: number) {}
17
18 multiply(other: Matrix): Matrix {
19 // Implementation
20 return new Matrix(this.rows, other.cols);
21 }
22}
23
24export interface Point {
25 x: number;
26 y: number;
27}
28
29export namespace Geometry {
30 export function distance(p1: Point, p2: Point): number {
31 return Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
32 }
33
34 export function midpoint(p1: Point, p2: Point): Point {
35 return {
36 x: (p1.x + p2.x) / 2,
37 y: (p1.y + p2.y) / 2
38 };
39 }
40}
41
42// dist/math-utils.d.ts - Generated declaration file
43export declare function fibonacci(n: number): number;
44export declare function isPrime(n: number): boolean;
45
46export declare class Matrix {
47 rows: number;
48 cols: number;
49 constructor(rows: number, cols: number);
50 multiply(other: Matrix): Matrix;
51}
52
53export interface Point {
54 x: number;
55 y: number;
56}
57
58export declare namespace Geometry {
59 function distance(p1: Point, p2: Point): number;
60 function midpoint(p1: Point, p2: Point): Point;
61}Ambient Modules and Global Augmentation:
1// types/global-augmentation.d.ts
2import 'express';
3
4declare global {
5 // Extending built-in types
6 interface Array<T> {
7 last(): T | undefined;
8 first(): T | undefined;
9 }
10
11 interface String {
12 capitalize(): string;
13 truncate(length: number): string;
14 }
15
16 // Custom global functions
17 function assert(condition: any, message?: string): asserts condition;
18 function invariant(condition: any, message?: string): asserts condition;
19
20 // Environment-specific globals
21 const __DEV__: boolean;
22 const __VERSION__: string;
23 const __BUILD_TIME__: string;
24}
25
26// Extending third-party module types
27declare module 'express' {
28 interface Request {
29 user?: {
30 id: string;
31 email: string;
32 role: string;
33 };
34 sessionId?: string;
35 }
36
37 interface Response {
38 success(data?: any): Response;
39 error(message: string, code?: number): Response;
40 }
41}
42
43// Implementation of global extensions
44Array.prototype.last = function <T>(this: T[]): T | undefined {
45 return this[this.length - 1];
46};
47
48Array.prototype.first = function <T>(this: T[]): T | undefined {
49 return this[0];
50};
51
52String.prototype.capitalize = function (this: string): string {
53 return this.charAt(0).toUpperCase() + this.slice(1);
54};
55
56String.prototype.truncate = function (this: string, length: number): string {
57 return this.length > length ? this.slice(0, length) + '...' : this;
58};
59
60// Usage with full type safety
61const numbers = [1, 2, 3, 4, 5];
62console.log(numbers.first()); // 1
63console.log(numbers.last()); // 5
64
65const text = "hello world";
66console.log(text.capitalize()); // "Hello world"
67console.log(text.truncate(5)); // "hello..."Type-Only Imports and Exports:
1// types.ts
2export interface User {
3 id: string;
4 name: string;
5}
6
7export interface Product {
8 id: string;
9 name: string;
10 price: number;
11}
12
13export type UserRole = 'admin' | 'user' | 'moderator';
14
15// service.ts
16import type { User, Product, UserRole } from './types';
17import { validateEmail } from './validation'; // Runtime import
18
19// Type-only imports don't appear in compiled JavaScript
20export class UserService {
21 async createUser(userData: Omit<User, 'id'>): Promise<User> {
22 // Implementation using runtime validation
23 if (!validateEmail(userData.email)) {
24 throw new Error('Invalid email');
25 }
26 return { id: 'generated-id', ...userData };
27 }
28
29 async assignRole(userId: string, role: UserRole): Promise<void> {
30 // Implementation
31 }
32}
33
34// Re-exporting types
35export type { User, Product } from './types';
36
37// Mixed runtime and type exports
38export { UserService } from './services/user';
39export type { UserServiceConfig } from './services/user';
40
41// Conditional type exports based on environment
42declare const isDevelopment: boolean;
43
44export type DevOnlyType = typeof isDevelopment extends true
45 ? { debugInfo: string }
46 : never;Module Concatenation and Tree Shaking:
1// utils/string.ts
2export function capitalize(str: string): string {
3 return str.charAt(0).toUpperCase() + str.slice(1);
4}
5
6export function truncate(str: string, length: number): string {
7 return str.length > length ? str.slice(0, length) + '...' : str;
8}
9
10export function slugify(str: string): string {
11 return str.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '');
12}
13
14// utils/array.ts
15export function chunk<T>(array: T[], size: number): T[][] {
16 const chunks: T[][] = [];
17 for (let i = 0; i < array.length; i += size) {
18 chunks.push(array.slice(i, i + size));
19 }
20 return chunks;
21}
22
23export function unique<T>(array: T[]): T[] {
24 return Array.from(new Set(array));
25}
26
27// utils/index.ts - Tree-shakeable barrel export
28export { capitalize, truncate } from './string'; // Only these will be bundled
29export { chunk } from './array'; // Only this will be bundled
30
31// main.ts - Only imports what's needed
32import { capitalize, chunk } from './utils';
33
34// slugify and unique won't be included in the bundle
35console.log(capitalize('hello'));
36console.log(chunk([1, 2, 3, 4], 2));While modern TypeScript favors ES modules, understanding namespaces is important for legacy code and specific organizational patterns.
Basic Namespace Patterns:
1// Traditional namespace syntax
2namespace Utilities {
3 export function formatDate(date: Date): string {
4 return date.toLocaleDateString();
5 }
6
7 export function formatCurrency(amount: number, currency: string = 'USD'): string {
8 return new Intl.NumberFormat('en-US', {
9 style: 'currency',
10 currency
11 }).format(amount);
12 }
13
14 export namespace Validation {
15 export function isEmail(email: string): boolean {
16 return email.includes('@');
17 }
18
19 export function isPhoneNumber(phone: string): boolean {
20 return /^\+?[1-9]\d{1,14}$/.test(phone);
21 }
22 }
23}
24
25// Usage
26console.log(Utilities.formatDate(new Date()));
27console.log(Utilities.formatCurrency(29.99));
28console.log(Utilities.Validation.isEmail('[email protected]'));
29
30// Alternative namespace syntax using module
31module Database {
32 export interface Connection {
33 host: string;
34 port: number;
35 database: string;
36 }
37
38 export class MySQLConnection implements Connection {
39 constructor(
40 public host: string,
41 public port: number,
42 public database: string
43 ) {}
44
45 connect(): Promise<void> {
46 return Promise.resolve();
47 }
48 }
49
50 export class PostgreSQLConnection implements Connection {
51 constructor(
52 public host: string,
53 public port: number,
54 public database: string
55 ) {}
56
57 connect(): Promise<void> {
58 return Promise.resolve();
59 }
60 }
61}Namespace Merging:
1// file1.ts
2namespace API {
3 export interface User {
4 id: string;
5 name: string;
6 }
7
8 export function getUser(id: string): Promise<User> {
9 return fetch(`/api/users/${id}`).then(res => res.json());
10 }
11}
12
13// file2.ts - Namespace merging
14namespace API {
15 export interface Product {
16 id: string;
17 name: string;
18 price: number;
19 }
20
21 export function getProduct(id: string): Promise<Product> {
22 return fetch(`/api/products/${id}`).then(res => res.json());
23 }
24}
25
26// file3.ts - Further merging
27namespace API {
28 export namespace V2 {
29 export interface User {
30 id: string;
31 name: string;
32 email: string;
33 createdAt: Date;
34 }
35
36 export function getUser(id: string): Promise<User> {
37 return fetch(`/api/v2/users/${id}`).then(res => res.json());
38 }
39 }
40}
41
42// Usage - all merged into single namespace
43const user = await API.getUser('123');
44const product = await API.getProduct('456');
45const userV2 = await API.V2.getUser('789');Converting Namespaces to Modules:
1// Before: Namespace approach
2namespace MathUtils {
3 export function add(a: number, b: number): number {
4 return a + b;
5 }
6
7 export function multiply(a: number, b: number): number {
8 return a * b;
9 }
10
11 export namespace Geometry {
12 export function distance(x1: number, y1: number, x2: number, y2: number): number {
13 return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
14 }
15 }
16}
17
18// After: Module approach
19// math/basic.ts
20export function add(a: number, b: number): number {
21 return a + b;
22}
23
24export function multiply(a: number, b: number): number {
25 return a * b;
26}
27
28// math/geometry.ts
29export function distance(x1: number, y1: number, x2: number, y2: number): number {
30 return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
31}
32
33// math/index.ts
34export * as Basic from './basic';
35export * as Geometry from './geometry';
36
37// Or flat exports
38export { add, multiply } from './basic';
39export { distance } from './geometry';
40
41// Usage comparison
42// Namespace: MathUtils.Geometry.distance(0, 0, 3, 4)
43// Module: import { Geometry } from './math'; Geometry.distance(0, 0, 3, 4)
44// Module flat: import { distance } from './math'; distance(0, 0, 3, 4)Module vs Namespace Trade-offs:
1// Namespace advantages: Global access, merging, single import
2namespace GlobalConfig {
3 export let apiUrl = 'https://api.example.com';
4 export let timeout = 5000;
5
6 export function updateConfig(newConfig: Partial<typeof GlobalConfig>): void {
7 Object.assign(GlobalConfig, newConfig);
8 }
9
10 export namespace Development {
11 export const apiUrl = 'http://localhost:3000/api';
12 export const enableDebug = true;
13 }
14}
15
16// Module advantages: Tree shaking, static analysis, better tooling
17// config/api.ts
18export const API_URL = process.env.NODE_ENV === 'development'
19 ? 'http://localhost:3000/api'
20 : 'https://api.example.com';
21
22export const TIMEOUT = 5000;
23
24// config/development.ts
25export const ENABLE_DEBUG = process.env.NODE_ENV === 'development';
26
27// config/index.ts
28export * from './api';
29export * from './development';
30
31// Better for modern tooling
32import { API_URL, TIMEOUT } from './config';Ambient Namespaces for Libraries:
1// types/jquery.d.ts
2declare namespace JQuery {
3 interface Ajax {
4 url?: string;
5 method?: string;
6 data?: any;
7 success?: (data: any) => void;
8 error?: (xhr: any, status: string, error: string) => void;
9 }
10}
11
12declare namespace $ {
13 function ajax(settings: JQuery.Ajax): void;
14 function get(url: string): Promise<any>;
15 function post(url: string, data: any): Promise<any>;
16}
17
18declare const jQuery: typeof $;
19
20// types/google-maps.d.ts
21declare namespace google {
22 namespace maps {
23 class Map {
24 constructor(element: HTMLElement, options: MapOptions);
25 }
26
27 interface MapOptions {
28 center: LatLng;
29 zoom: number;
30 }
31
32 class LatLng {
33 constructor(lat: number, lng: number);
34 }
35
36 class Marker {
37 constructor(options: MarkerOptions);
38 }
39
40 interface MarkerOptions {
41 position: LatLng;
42 map: Map;
43 title?: string;
44 }
45 }
46}
47
48// Usage
49$.ajax({
50 url: '/api/data',
51 method: 'GET',
52 success: (data) => console.log(data)
53});
54
55const map = new google.maps.Map(document.getElementById('map')!, {
56 center: new google.maps.LatLng(40.7128, -74.0060),
57 zoom: 13
58});Large TypeScript projects require thoughtful organization to maintain scalability, developer productivity, and code quality.
Feature-Based Architecture:
1// Project structure
2src/
3├── features/
4│ ├── authentication/
5│ │ ├── components/
6│ │ │ ├── LoginForm.tsx
7│ │ │ ├── SignupForm.tsx
8│ │ │ └── index.ts
9│ │ ├── services/
10│ │ │ ├── authService.ts
11│ │ │ └── tokenService.ts
12│ │ ├── types/
13│ │ │ └── auth.types.ts
14│ │ ├── hooks/
15│ │ │ └── useAuth.ts
16│ │ └── index.ts
17│ ├── dashboard/
18│ ├── user-management/
19│ └── reporting/
20├── shared/
21│ ├── components/
22│ ├── services/
23│ ├── types/
24│ ├── utils/
25│ └── constants/
26├── core/
27│ ├── api/
28│ ├── routing/
29│ ├── store/
30│ └── config/
31└── app/
32
33// features/authentication/types/auth.types.ts
34export interface User {
35 id: string;
36 email: string;
37 name: string;
38 role: UserRole;
39 permissions: Permission[];
40}
41
42export interface LoginCredentials {
43 email: string;
44 password: string;
45}
46
47export interface AuthState {
48 user: User | null;
49 isAuthenticated: boolean;
50 isLoading: boolean;
51}
52
53export type UserRole = 'admin' | 'user' | 'moderator';
54export type Permission = 'read' | 'write' | 'delete' | 'manage';
55
56// features/authentication/services/authService.ts
57import type { User, LoginCredentials } from '../types/auth.types';
58import { ApiClient } from '@/core/api';
59
60export class AuthService {
61 private apiClient = new ApiClient();
62
63 async login(credentials: LoginCredentials): Promise<User> {
64 const response = await this.apiClient.post('/auth/login', credentials);
65 return response.data;
66 }
67
68 async logout(): Promise<void> {
69 await this.apiClient.post('/auth/logout');
70 }
71
72 async getCurrentUser(): Promise<User> {
73 const response = await this.apiClient.get('/auth/me');
74 return response.data;
75 }
76}
77
78// features/authentication/index.ts - Feature barrel export
79export { AuthService } from './services/authService';
80export { TokenService } from './services/tokenService';
81export { LoginForm, SignupForm } from './components';
82export { useAuth } from './hooks/useAuth';
83export type { User, LoginCredentials, AuthState } from './types/auth.types';Layered Architecture Pattern:
1// Layered architecture structure
2src/
3├── presentation/ # UI layer
4│ ├── components/
5│ ├── pages/
6│ ├── hooks/
7│ └── stores/
8├── application/ # Business logic layer
9│ ├── services/
10│ ├── useCases/
11│ ├── dto/
12│ └── interfaces/
13├── domain/ # Core business domain
14│ ├── entities/
15│ ├── valueObjects/
16│ ├── aggregates/
17│ └── repositories/
18├── infrastructure/ # External concerns
19│ ├── api/
20│ ├── database/
21│ ├── storage/
22│ └── external/
23└── shared/ # Cross-cutting concerns
24 ├── types/
25 ├── utils/
26 ├── constants/
27 └── errors/
28
29// domain/entities/User.ts
30export class User {
31 constructor(
32 public readonly id: UserId,
33 public readonly email: Email,
34 public readonly name: string,
35 private _role: UserRole
36 ) {}
37
38 get role(): UserRole {
39 return this._role;
40 }
41
42 changeRole(newRole: UserRole): void {
43 if (this._role === 'admin' && newRole !== 'admin') {
44 throw new Error('Cannot remove admin role');
45 }
46 this._role = newRole;
47 }
48
49 hasPermission(permission: Permission): boolean {
50 return RolePermissions[this._role].includes(permission);
51 }
52}
53
54// domain/valueObjects/Email.ts
55export class Email {
56 private constructor(private readonly value: string) {}
57
58 static create(email: string): Email {
59 if (!this.isValid(email)) {
60 throw new Error('Invalid email format');
61 }
62 return new Email(email);
63 }
64
65 private static isValid(email: string): boolean {
66 return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
67 }
68
69 toString(): string {
70 return this.value;
71 }
72}
73
74// application/useCases/CreateUserUseCase.ts
75import { User } from '@/domain/entities/User';
76import { Email } from '@/domain/valueObjects/Email';
77import { UserRepository } from '@/domain/repositories/UserRepository';
78
79interface CreateUserRequest {
80 email: string;
81 name: string;
82 role: UserRole;
83}
84
85export class CreateUserUseCase {
86 constructor(private userRepository: UserRepository) {}
87
88 async execute(request: CreateUserRequest): Promise<User> {
89 const email = Email.create(request.email);
90
91 const existingUser = await this.userRepository.findByEmail(email);
92 if (existingUser) {
93 throw new Error('User already exists');
94 }
95
96 const user = new User(
97 this.generateUserId(),
98 email,
99 request.name,
100 request.role
101 );
102
103 await this.userRepository.save(user);
104 return user;
105 }
106
107 private generateUserId(): UserId {
108 return `user-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` as UserId;
109 }
110}Monorepo and Package Organization:
1// Monorepo structure with shared packages
2packages/
3├── core/ # Shared core functionality
4│ ├── src/
5│ │ ├── types/
6│ │ ├── utils/
7│ │ ├── validation/
8│ │ └── errors/
9│ ├── package.json
10│ └── tsconfig.json
11├── ui-components/ # Shared UI library
12│ ├── src/
13│ │ ├── Button/
14│ │ ├── Input/
15│ │ ├── Modal/
16│ │ └── index.ts
17│ ├── package.json
18│ └── tsconfig.json
19├── api-client/ # Shared API client
20│ ├── src/
21│ │ ├── client.ts
22│ │ ├── types.ts
23│ │ └── endpoints/
24│ ├── package.json
25│ └── tsconfig.json
26├── web-app/ # Main web application
27│ ├── src/
28│ ├── package.json
29│ └── tsconfig.json
30├── mobile-app/ # Mobile application
31│ ├── src/
32│ ├── package.json
33│ └── tsconfig.json
34└── admin-panel/ # Admin interface
35 ├── src/
36 ├── package.json
37 └── tsconfig.json
38
39// packages/core/src/types/common.ts
40export interface BaseEntity {
41 id: string;
42 createdAt: Date;
43 updatedAt: Date;
44}
45
46export interface ApiResponse<T> {
47 data: T;
48 status: number;
49 message: string;
50}
51
52export type Result<T, E = Error> =
53 | { success: true; data: T }
54 | { success: false; error: E };
55
56// packages/core/src/utils/result.ts
57export class ResultUtils {
58 static success<T>(data: T): Result<T> {
59 return { success: true, data };
60 }
61
62 static failure<E>(error: E): Result<never, E> {
63 return { success: false, error };
64 }
65
66 static isSuccess<T, E>(result: Result<T, E>): result is { success: true; data: T } {
67 return result.success;
68 }
69
70 static isFailure<T, E>(result: Result<T, E>): result is { success: false; error: E } {
71 return !result.success;
72 }
73}
74
75// packages/ui-components/src/Button/Button.tsx
76import React from 'react';
77
78export interface ButtonProps {
79 variant: 'primary' | 'secondary' | 'danger';
80 size: 'small' | 'medium' | 'large';
81 disabled?: boolean;
82 loading?: boolean;
83 onClick?: () => void;
84 children: React.ReactNode;
85}
86
87export const Button: React.FC<ButtonProps> = ({
88 variant,
89 size,
90 disabled,
91 loading,
92 onClick,
93 children
94}) => {
95 return (
96 <button
97 className={`btn btn--${variant} btn--${size}`}
98 disabled={disabled || loading}
99 onClick={onClick}
100 >
101 {loading ? 'Loading...' : children}
102 </button>
103 );
104};
105
106// apps/web-app/package.json dependencies
107{
108 "dependencies": {
109 "@company/core": "workspace:*",
110 "@company/ui-components": "workspace:*",
111 "@company/api-client": "workspace:*"
112 }
113}
114
115// apps/web-app/src/components/UserForm.tsx
116import React from 'react';
117import { Button } from '@company/ui-components';
118import { Result, ResultUtils } from '@company/core';
119import { UserApiClient } from '@company/api-client';Configuration and Environment Management:
1// config/base.ts
2export interface AppConfig {
3 api: {
4 baseUrl: string;
5 timeout: number;
6 retries: number;
7 };
8 auth: {
9 tokenKey: string;
10 refreshTokenKey: string;
11 tokenExpiry: number;
12 };
13 features: {
14 analytics: boolean;
15 chat: boolean;
16 darkMode: boolean;
17 };
18 monitoring: {
19 sentry: {
20 dsn: string;
21 environment: string;
22 };
23 analytics: {
24 trackingId: string;
25 };
26 };
27}
28
29// config/development.ts
30import { AppConfig } from './base';
31
32export const developmentConfig: AppConfig = {
33 api: {
34 baseUrl: 'http://localhost:3000/api',
35 timeout: 10000,
36 retries: 3
37 },
38 auth: {
39 tokenKey: 'dev_auth_token',
40 refreshTokenKey: 'dev_refresh_token',
41 tokenExpiry: 3600000 // 1 hour
42 },
43 features: {
44 analytics: false,
45 chat: true,
46 darkMode: true
47 },
48 monitoring: {
49 sentry: {
50 dsn: '',
51 environment: 'development'
52 },
53 analytics: {
54 trackingId: ''
55 }
56 }
57};
58
59// config/production.ts
60import { AppConfig } from './base';
61
62export const productionConfig: AppConfig = {
63 api: {
64 baseUrl: process.env.API_BASE_URL!,
65 timeout: 5000,
66 retries: 2
67 },
68 auth: {
69 tokenKey: 'auth_token',
70 refreshTokenKey: 'refresh_token',
71 tokenExpiry: 1800000 // 30 minutes
72 },
73 features: {
74 analytics: true,
75 chat: true,
76 darkMode: true
77 },
78 monitoring: {
79 sentry: {
80 dsn: process.env.SENTRY_DSN!,
81 environment: 'production'
82 },
83 analytics: {
84 trackingId: process.env.GA_TRACKING_ID!
85 }
86 }
87};
88
89// config/index.ts
90import { developmentConfig } from './development';
91import { productionConfig } from './production';
92import { testConfig } from './test';
93
94const configs = {
95 development: developmentConfig,
96 production: productionConfig,
97 test: testConfig
98};
99
100export const config = configs[process.env.NODE_ENV as keyof typeof configs] || developmentConfig;
101export type { AppConfig } from './base';Your progress is saved in this browser, on this device only.