← Back to TypeScript Course | Chapter 6: Classes | Lesson 7 of 9

Abstract Classes

An abstract class is a base class that cannot be instantiated directly. It can define shared behavior and require derived classes to implement abstract methods.

Creating an Abstract Class

An abstract class is declared with the abstract keyword and is designed to be extended, not instantiated directly — attempting new on an abstract class is a compile-time error.

Example: Creating an Abstract Class

typescript
abstract class Shape {
  abstract area(): number;
}
// new Shape(); // rejected: cannot instantiate an abstract class
class Circle extends Shape {
  constructor(public radius: number) { super(); }
  area() { return 3.14 * this.radius ** 2; }
}
console.log(new Circle(5).area());

Abstract Methods

An abstract method has a declaration but no implementation in the abstract base class; every concrete subclass is required to supply its own implementation, which the compiler enforces.

Example: Abstract Methods

typescript
abstract class Animal {
  abstract makeSound(): string;
}
class Dog extends Animal {
  makeSound() { return "Woof"; }
}
console.log(new Dog().makeSound());

Concrete Methods in Abstract Classes

Abstract classes can also contain normal concrete methods alongside abstract ones, letting shared, already-working logic live in the base class while only the parts that genuinely vary are left for subclasses to fill in.

Example: Concrete Methods in Abstract Classes

typescript
abstract class Animal {
  abstract makeSound(): string;
  describe() {
    return `This animal says: ${this.makeSound()}`;
  }
}
class Cat extends Animal {
  makeSound() { return "Meow"; }
}
console.log(new Cat().describe());

Abstract Classes and Polymorphism

An abstract class can be used as a type for references to different concrete subclasses, so code written against the abstract type works uniformly no matter which specific subclass is passed in at runtime.

Example: Abstract Classes and Polymorphism

typescript
abstract class Shape {
  abstract area(): number;
}
class Square extends Shape {
  constructor(public side: number) { super(); }
  area() { return this.side ** 2; }
}
class Circle extends Shape {
  constructor(public radius: number) { super(); }
  area() { return 3.14 * this.radius ** 2; }
}
const shapes: Shape[] = [new Square(4), new Circle(2)];
shapes.forEach((s) => console.log(s.area()));

When to Use Abstract Classes

Abstract classes are useful when related classes share real implementation but must also provide their own version of at least one method — if there's nothing shared at all, a plain interface is usually the better fit.

Example: When to Use Abstract Classes

typescript
abstract class Employee {
  constructor(public name: string) {}
  abstract calculateSalary(): number;
  printPaycheck() {
    console.log(`${this.name}: $${this.calculateSalary()}`);
  }
}
class Manager extends Employee {
  calculateSalary() { return 5000; }
}
new Manager("Alia").printPaycheck();

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.