Abstract Classes and implements
Introduction
Not every class should be instantiated directly. Abstract classes define shared behavior and leave specific pieces to subclasses. implements connects classes (and sometimes other patterns) to interface contracts so callers depend on capabilities, not concrete types. This chapter ties object-oriented structure to TypeScript’s type checking.
Prerequisites
abstract Classes and Methods
Mark a class abstract when it is a base, not a complete implementation:
abstract class Notification {
constructor(public recipient: string) {}
abstract render(): string;
send(): void {
const body = this.render();
console.log(`To: ${this.recipient}\n${body}`);
}
}Code explanation:
abstract render()must be implemented by concrete subclassessend()is concrete shared logic usingrender()
Concrete subclass:
You cannot instantiate the abstract base:
// const n = new Notification("x"); // Error: Cannot create an instance of an abstract classabstract vs interface
abstract class | interface | |
|---|---|---|
| Runtime | Emits JavaScript class | Erased—no runtime |
| Implementation | Can include concrete methods and fields | Only shape—no method bodies |
| Inheritance | Single extends chain | Multiple implements |
| Use when | Shared code + template method pattern | Pure contracts, multiple roles |
interface Serializable {
toJSON(): string;
}
abstract class Model implements Serializable {
abstract id: string;
toJSON(): string {
return JSON.stringify({ id: this.id });
}
}Code explanation:
Modelprovides defaulttoJSONwhile forcing subclasses to defineidimplements Serializabledocuments the capability for type checkers
implements Multiple Interfaces
Every interface member must be present with compatible types.
Structuring a Small Hierarchy
Code explanation:
chargeis the template;processis the hook subclasses customize- Return type
Promise<{ ok: boolean }>documents async behavior
When to Prefer interface Only
Use interfaces (no abstract class) when:
- You only need a shape, no shared implementation
- Multiple unrelated classes must satisfy the same contract
- You want to avoid inheritance depth
Functions depend on Logger, not a specific class.
implements with Generics (Preview)
Comparable<Version> keeps comparisons type-safe.
Common Mistakes
| Mistake | Result | Fix |
|---|---|---|
Forget super() in subclass | Error in constructor | Call super(...) first |
| Leave abstract method unimplemented | Class stays abstract / error | Implement all abstract members |
implements without matching types | Compile errors | Align method signatures |
| Deep inheritance trees | Hard to change | Favor composition + interfaces |
FAQ
Can an abstract class implement an interface?
Yes. abstract class X implements Y is common for shared defaults plus a contract.
Can interfaces extend abstract classes?
No. Interfaces extend other interfaces (or use extends with object types). Classes extend abstract classes.
abstract methods in interfaces?
Interfaces can declare method signatures without bodies—similar idea, different syntax. Use interface for pure contracts; abstract class when sharing code.
Multiple inheritance?
TypeScript allows one extends and multiple implements. No multiple class extension.
Are abstract classes used in React?
Function components dominate; classes appear in older code and some libraries. Understanding them still matters for Node services and domain models.
Should I mark every base class abstract?
Only when instantiation would be wrong or incomplete. Otherwise a normal class is fine.