正在加载,请稍候…

SOLID Principles in TypeScript: Practical Examples

Master the five SOLID principles with real TypeScript examples. Learn how SRP, OCP, LSP, ISP, and DIP improve code maintainability.

SOLID Principles in TypeScript: Practical Examples

SOLID principles guide you toward flexible, maintainable object-oriented code.

Single Responsibility Principle (SRP)

A class should have only one reason to change.

// Bad: handles both user data and email sending
class UserService {
  createUser(name: string, email: string) { /* ... */ }
  sendWelcomeEmail(email: string) { /* ... */ }
  generateReport() { /* ... */ }
}

// Good: separate responsibilities
class UserRepository {
  create(user: User): Promise<User> { /* ... */ }
  findById(id: string): Promise<User> { /* ... */ }
}

class EmailService {
  sendWelcome(email: string): Promise<void> { /* ... */ }
}

class UserReportGenerator {
  generate(): Report { /* ... */ }
}

Open/Closed Principle (OCP)

Open for extension, closed for modification.

// Bad: modify class to add discount types
class OrderCalculator {
  calculate(order: Order): number {
    if (order.type === 'regular') return order.total;
    if (order.type === 'premium') return order.total * 0.9;
    // Must modify class for new types
  }
}

// Good: extend without modifying
interface DiscountStrategy {
  apply(total: number): number;
}

class RegularDiscount implements DiscountStrategy {
  apply(total: number) { return total; }
}

class PremiumDiscount implements DiscountStrategy {
  apply(total: number) { return total * 0.9; }
}

class BlackFridayDiscount implements DiscountStrategy {
  apply(total: number) { return total * 0.7; }
}

class OrderCalculator {
  constructor(private discount: DiscountStrategy) {}
  calculate(order: Order): number {
    return this.discount.apply(order.total);
  }
}

Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

// Bad: Square breaks Rectangle contract
class Rectangle {
  setWidth(w: number) { this.width = w; }
  setHeight(h: number) { this.height = h; }
  area() { return this.width * this.height; }
}

class Square extends Rectangle {
  setWidth(w: number) { this.width = w; this.height = w; } // Breaks LSP!
}

// Good: separate hierarchy
interface Shape {
  area(): number;
}
class Rectangle implements Shape { /* ... */ }
class Square implements Shape { /* ... */ }

Interface Segregation Principle (ISP)

Clients should not depend on interfaces they don't use.

// Bad: fat interface
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
}

// Good: small, focused interfaces
interface Workable { work(): void; }
interface Eatable { eat(): void; }
interface Sleepable { sleep(): void; }

class Human implements Workable, Eatable, Sleepable { /* ... */ }
class Robot implements Workable { /* only work */ }

Dependency Inversion Principle (DIP)

Depend on abstractions, not concretions.

// Bad: depends on concrete implementation
class OrderService {
  private db = new MySQLDatabase(); // hard dependency
  saveOrder(order: Order) { this.db.save(order); }
}

// Good: depends on abstraction
interface Database {
  save<T>(data: T): Promise<void>;
  find<T>(id: string): Promise<T>;
}

class OrderService {
  constructor(private db: Database) {} // injected
  async saveOrder(order: Order) { await this.db.save(order); }
}

// Compose in application root
const service = new OrderService(new PostgresDatabase());

SOLID principles make systems easier to test, extend, and maintain.