implements vs Abstract Classes

Two ways to enforce a contract on a class, and when each earns its keep.

Both implements and extends abstract make a class honour a contract, but they differ in what they carry.

implements an interface

implements is a pure compile-time check: the class must have the required members, but inherits nothing. A class can implement many interfaces at once.

interface Serializable { toJSON(): string }
interface Comparable<T> { compareTo(o: T): number }
class Money implements Serializable, Comparable<Money> { /* must supply both */ }

extends an abstract class

An abstract base can ship real code and state down to subclasses, but a class extends exactly one. It is single inheritance plus shared implementation.

How to choose

  • Need to guarantee a shape only, and mix several? Use implements with interfaces.
  • Need to share concrete behaviour or protected state? Use an abstract base.

They are not rivals β€” a class often extends one abstract base and implements a couple of interfaces.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A team uses implements when multiple unrelated classes must satisfy the same interface without sharing any implementation.
  • A template-method pattern uses an abstract class to provide a shared algorithm with abstract hook methods for specialisation.
  • A plugin system uses implements to allow third-party classes to satisfy a Plugin interface without inheriting any base class.

More examples

implements interface β€” no shared code

Two unrelated classes implement the same interface; they share a contract but no implementation.

Example Β· ts
interface Drawable {
  draw(): void;
}

class Circle implements Drawable {
  draw(): void { console.log('Drawing circle'); }
}

class Square implements Drawable {
  draw(): void { console.log('Drawing square'); }
}

function render(shapes: Drawable[]): void {
  shapes.forEach((s) => s.draw());
}

Abstract class β€” shared code + contract

Abstract class provides the shared print() implementation and mandates generate(); subclasses add specific content.

Example Β· ts
abstract class Report {
  abstract generate(): string[]; // must implement

  print(): void {
    this.generate().forEach((line) => console.log(line));
  }
}

class SalesReport extends Report {
  generate(): string[] { return ['Total: $1200', 'Units: 40']; }
}

new SalesReport().print();

Class that extends and implements

A class can extend an abstract base and implement an interface simultaneously, combining both patterns when both are needed.

Example Β· ts
interface Serializable { serialize(): string; }

abstract class Entity {
  abstract id: number;
}

class Product extends Entity implements Serializable {
  id = 1;
  name = 'Pen';

  serialize(): string {
    return JSON.stringify({ id: this.id, name: this.name });
  }
}

Discussion

  • Be the first to comment on this lesson.
implements vs Abstract Classes β€” TypeScript | SoundsCode