TypeScript Abstract Methods Explained Simply

TypeScript Abstract Methods Explained Simply

Abstract methods in TypeScript are like blueprints for methods that must be implemented by some child class. Think of them as contracts that say “any class that extends this abstract class must have these methods.”

What Are Abstract Methods?

An abstract method is a method that is declared in a class, but not implemented. It’s like saying “this method must exist, but I won’t tell you how to implement it.” The actual implementation is left to the classes that inherit from the abstract class.

abstract class Animal {
  abstract makeSound(): void; // This method must be implemented by child classes
}

Why Use Abstract Methods?

Abstract methods are useful when you want to:

  • Define a common interface for related classes
  • Force child classes to implement specific behavior
  • Create a template that can be customized

Creating Abstract Classes and Methods

To create an abstract method, you need an abstract class. Here’s the syntax:

abstract class Vehicle {
  abstract startEngine(): void;
  abstract stopEngine(): void;
  
  // Regular methods can also exist
  getInfo(): string {
    return "This is a vehicle";
  }
}

Implementing Abstract Classes

When you extend an abstract class, you must implement all abstract methods:

class Car extends Vehicle {
  startEngine(): void {
    console.log("Car engine started");
  }
  
  stopEngine(): void {
    console.log("Car engine stopped");
  }
}

class Motorcycle extends Vehicle {
  startEngine(): void {
    console.log("Motorcycle engine started");
  }
  
  stopEngine(): void {
    console.log("Motorcycle engine stopped");
  }
}

Abstract Properties

You can also have abstract properties that must be implemented:

abstract class Shape {
  abstract area: number;
  abstract perimeter: number;
  
  abstract calculateArea(): number;
}

class Circle extends Shape {
  area: number = 0;
  perimeter: number = 0;
  
  constructor(public radius: number) {
    super();
    this.calculateArea();
    this.calculatePerimeter();
  }
  
  calculateArea(): number {
    this.area = Math.PI * this.radius * this.radius;
    return this.area;
  }
  
  calculatePerimeter(): number {
    this.perimeter = 2 * Math.PI * this.radius;
    return this.perimeter;
  }
}

Abstract Classes vs Interfaces

Abstract classes and interfaces are similar but have key differences:

Abstract Classes:

  • Can have implementation details
  • Can have constructors
  • Can have access modifiers (e.g. public, private)
  • Can’t be instantiated directly

Interfaces:

  • Only defines the structure
  • No implementation
  • Lighter weight

Real-World Example: Employee Management

Here’s a practical example using an employee management system:

abstract class Employee {
  constructor(
    public name: string,
    public id: string,
    public baseSalary: number
  ) {}
  
  abstract calculateSalary(): number;
  abstract getRole(): string;
  
  getInfo(): string {
    return `${this.name} (${this.id}) - ${this.getRole()}`;
  }
}

class FullTimeEmployee extends Employee {
  constructor(
    name: string,
    id: string,
    baseSalary: number,
    public benefits: number
  ) {
    super(name, id, baseSalary);
  }
  
  calculateSalary(): number {
    return this.baseSalary + this.benefits;
  }
  
  getRole(): string {
    return "Full Time Employee";
  }
}

class Contractor extends Employee {
  constructor(
    name: string,
    id: string,
    baseSalary: number,
    public hoursWorked: number
  ) {
    super(name, id, baseSalary);
  }
  
  calculateSalary(): number {
    return this.baseSalary * this.hoursWorked;
  }
  
  getRole(): string {
    return "Contractor";
  }
}

Best Practices

  1. Don’t overuse abstract classes - Use them when you need shared implementation
  2. Keep abstract methods focused - Each should have a single, clear purpose
  3. Provide meaningful default implementations - When possible, give child classes a starting point
  4. Use descriptive names - Abstract method names should clearly indicate their purpose

Common Pitfalls

  1. Forgetting to implement abstract methods - TypeScript will catch this at compile time
  2. Making everything abstract - This defeats the purpose of having shared implementation. If you make everything abstract, you’re basically just creating an interface.
  3. Complex abstract method signatures - Keep them simple and focused

When to Use Abstract Methods

Use abstract methods when:

  • You have related classes that share some behavior
  • You want to enforce a common interface
  • You need to provide some implementation while leaving parts customizable

Don’t use them when:

  • You only need to define structure (use interfaces instead)
  • You don’t have shared implementation
  • You want maximum flexibility

Conclusion

Abstract methods in TypeScript provide a powerful way to create reusable class hierarchies while enforcing consistent behavior. They’re perfect for scenarios where you want to share some implementation while allowing customization of specific methods.

Remember: abstract methods are like promises that child classes must fulfill. They ensure consistency while maintaining flexibility in your object-oriented designs.

If this article was helpful, tweet it!