GAZAR

Principal Engineer | Mentor

Prefer Composition Over Inheritance in TypeScript: Best Practices and Examples

Prefer Composition Over Inheritance in TypeScript: Best Practices and Examples

While inheritance allows for code reuse through subclassing, it can lead to tight coupling, brittle designs, and inheritance hierarchies that are difficult to maintain. In contrast, composition promotes a more flexible and modular approach by assembling objects from smaller, reusable components. This article explores the benefits of preferring composition over inheritance in TypeScript and provides best practices and examples to guide developers in leveraging composition effectively.

Example of Composition

class Engine {
  start(): void {
    console.log('Engine started');
  }
}

class Wheel {
  rotate(): void {
    console.log('Wheel rotating');
  }
}

class Car {
  private engine: Engine;
  private wheels: Wheel[];

  constructor() {
    this.engine = new Engine();
    this.wheels = [new Wheel(), new Wheel(), new Wheel(), new Wheel()];
  }

  start(): void {
    this.engine.start();
    this.wheels.forEach(wheel => wheel.rotate());
    console.log('Car started');
  }
}

const car = new Car();
car.start();

By preferring composition over inheritance in TypeScript, developers can build more flexible, modular, and maintainable software systems. By embracing the principles of composition, encapsulation, loose coupling, and code reuse, developers can create cleaner, more extensible codebases that are easier to understand, test, and evolve over time.