How to Use Abstract Classes in TypeScript
Use abstract classes in TypeScript when multiple classes should share a base structure while forcing subclasses to implement required behavior. This is perfect for UI frameworks, domain models, game entities, and reusable service contracts.
What you’ll build or solve
You’ll learn how to use abstract classes in TypeScript with shared logic, abstract methods, and subclass implementations. You’ll also know when abstract classes are better than interfaces.
Learn TypeScript on Mimo
When this approach works best
This approach is the right choice when subclasses need both shared implementation and required method contracts.
Common real-world scenarios include:
- Base UI components
- Payment providers
- Shape renderers
- Game entities
- Service adapters
This is a bad idea when only the method shape matters and no shared implementation is needed.
Prerequisites
You only need:
- Basic TypeScript classes
- Inheritance
- Methods
- Access modifiers
Step-by-step instructions
Step 1: Create an abstract base class
Use the abstract keyword.
abstract class Shape {
constructor(public color: string) {}
abstract getArea(): number;
}
This class cannot be instantiated directly.
It defines shared structure plus a required method.
Step 2: Extend the abstract class
Child classes must implement all abstract methods.
class Circle extends Shape {
constructor(color: string, public radius: number) {
super(color);
}
getArea(): number {
return Math.PI * this.radius * this.radius;
}
}
Now the subclass becomes valid and reusable.
Step 3: Add shared concrete logic
Abstract classes can still include reusable methods.
abstract class Animal {
constructor(public name: string) {}
describe(): string {
return `Animal: ${this.name}`;
}
abstract speak(): string;
}
Subclasses reuse describe() while defining speak().
What to look for:
abstractprevents direct instantiation- Shared logic can live in the base class
- Abstract methods must be implemented
- Great for reusable contracts + logic
- Better than interfaces when shared code exists
Examples you can copy
Payment provider
abstract class PaymentProvider {
abstract charge(amount: number): void;
}
Base UI widget
abstract class Widget {
abstract render(): string;
}
Game character
abstract class Enemy {
abstract attack(): void;
}
Common mistakes and how to fix them
Mistake 1: Trying to instantiate the abstract class
What the reader might do:
const shape = new Shape("red");
Why it breaks: abstract classes cannot create direct instances.
Corrected approach:
Instantiate a concrete subclass.
Mistake 2: Forgetting to implement abstract methods
What the reader might do:
Extend the base class without defining getArea().
Why it breaks: the subclass stays abstract and cannot be instantiated.
Corrected approach:
Implement every abstract member.
Mistake 3: Using abstract classes when only types matter
What the reader might do:
Use an abstract class with no shared logic.
Why it breaks: an interface is simpler.
Corrected approach:
Use interfaces when behavior sharing is unnecessary.
Troubleshooting
If the subclass errors, implement all abstract methods.
If the base class is never meant to share logic, switch to an interface.
If new fails, instantiate the concrete subclass instead.
If the hierarchy gets too rigid, consider composition.
Quick recap
- Use abstract classes for shared logic + required contracts
- They cannot be instantiated directly
- Subclasses must implement abstract methods
- Great for reusable frameworks
- Prefer interfaces when no shared logic exists
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot