Abstract Classes

Base Classes That Can't Be Instantiated

Abstract Classes

`abstract` classes can't be `new`-ed directly. They declare shape + partial implementation; subclasses fill in the rest.

3 min read Level 2/5 #typescript#classes#abstract
What you'll learn
  • Declare an abstract class with abstract methods
  • Use a non-abstract base method for shared logic
  • Subclass to fill in the abstract parts

An abstract class can’t be instantiated. It exists to be extended — the base class declares some methods that subclasses must implement, plus shared logic that they inherit.

The Syntax

abstract class Shape {
  abstract area(): number;     // no body — subclass must define

  describe() {
    return `area = ${this.area().toFixed(2)}`;
  }
}

class Circle extends Shape {
  constructor(public r: number) { super(); }
  area() { return Math.PI * this.r ** 2; }
}

class Square extends Shape {
  constructor(public side: number) { super(); }
  area() { return this.side ** 2; }
}

new Shape();              // ✗ Cannot create an instance of an abstract class
new Circle(2).describe(); // "area = 12.57"

abstract on the class blocks new Shape(). abstract area() forces every subclass to implement it.

Why?

Two reasons:

  1. Force a contract. Subclasses must provide an area(). If they don’t, TS errors.
  2. Share base logic. describe() is defined once in the base — every subclass gets it for free.

You can think of it as interface + some shared implementation, in one declaration.

Mixing Abstract and Concrete

abstract class Animal {
  constructor(public name: string) {}

  abstract speak(): string;          // subclass must implement

  greet() {                          // shared
    return `${this.name} says ${this.speak()}`;
  }
}

class Cat extends Animal {
  speak() { return "meow"; }
}

new Cat("Salem").greet();   // "Salem says meow"

Trade-offs

Modern JS leans on composition over inheritance. Abstract classes are valuable when:

  • You have a stable hierarchy (shapes, AST nodes, parser states)
  • The base genuinely shares implementation

For loose plug-in style, an interface is often a better tool.

Up Next

Getters and setters — methods that look like fields.

Getters & Setters →