🔷 TypeScript Q28 / 101

What is abstract class in TypeScript?

AI-Powered Answer ✓ Answered

An abstract class in TypeScript is a special type of class that cannot be instantiated directly. It serves as a blueprint for other classes, defining common properties and methods that derived classes must or may implement. Abstract classes are primarily used to define a common interface and provide a base implementation for a group of related objects.

Definition

An abstract class is declared using the abstract keyword. It can contain both abstract members (methods and properties) and non-abstract (concrete) members. Abstract members are declared without an implementation; they must be implemented by any non-abstract derived class. Non-abstract members provide a default implementation that derived classes can inherit or override.

Key Characteristics

  • Cannot be instantiated: You cannot create an object directly from an abstract class using the new keyword.
  • Requires subclasses: Abstract classes are meant to be extended by other concrete classes.
  • Can have abstract members: They can declare methods and properties as abstract, meaning they don't have an implementation in the abstract class itself.
  • Abstract members must be implemented: Any non-abstract class that extends an abstract class must provide an implementation for all inherited abstract methods and properties.
  • Can have concrete members: They can also have regular (non-abstract) methods and properties with full implementations, which derived classes can inherit or override.
  • Acts as a base class: Provides a common contract and potentially partial implementation for derived classes.

When to Use Abstract Classes

  • Defining a common interface with partial implementation: When you want to define a common structure and some shared behavior, but also require subclasses to provide their specific implementations for certain operations.
  • Base classes for a family of related objects: To ensure that all derived classes adhere to a specific contract and share some foundational logic.
  • Encouraging specific behavior: When you want to force subclasses to implement certain methods, ensuring a particular functionality exists across all derived types.
  • Refactoring common code: To move common methods and properties from multiple concrete classes into a single base abstract class.

Example

Consider an example where we want to define different types of shapes, each with a method to calculate its area and a common method to display information.

typescript
abstract class Shape {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  // An abstract method that must be implemented by derived classes
  abstract getArea(): number;

  // A concrete method with an implementation
  displayInfo(): void {
    console.log(`This is a ${this.name} with an area of ${this.getArea()} square units.`);
  }
}

class Circle extends Shape {
  radius: number;

  constructor(name: string, radius: number) {
    super(name);
    this.radius = radius;
  }

  // Implementation of the abstract method
  getArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}

class Rectangle extends Shape {
  width: number;
  height: number;

  constructor(name: string, width: number, height: number) {
    super(name);
    this.width = width;
    this.height = height;
  }

  // Implementation of the abstract method
  getArea(): number {
    return this.width * this.height;
  }
}

// We cannot instantiate an abstract class directly
// const myShape = new Shape("Generic Shape"); // Error: Cannot create an instance of an abstract class.

const circle = new Circle("Circle", 10);
console.log(circle.getArea()); // Output: 314.159...
circle.displayInfo(); // Output: This is a Circle with an area of 314.159... square units.

const rectangle = new Rectangle("Rectangle", 5, 8);
console.log(rectangle.getArea()); // Output: 40
rectangle.displayInfo(); // Output: This is a Rectangle with an area of 40 square units.

Abstract Classes vs. Interfaces

While both abstract classes and interfaces define contracts, they have key differences:

  • Implementation: Interfaces only declare members (methods, properties) without implementation. Abstract classes can declare members and also provide concrete implementations.
  • Instantiation: Neither can be instantiated directly. However, an abstract class requires you to extend it, while an interface requires you to implement it.
  • Inheritance: A class can implement multiple interfaces but can only extend one abstract class (or any other class).
  • Constructors: Abstract classes can have constructors; interfaces cannot.
  • Access Modifiers: Abstract classes can have public, protected, and private members. Interfaces only implicitly have public members.

In essence, use an interface when you want to define a contract for what a class *can do*. Use an abstract class when you want to define a common base with some shared behavior and a contract for what a class *is* and *must do*.