0
0
Typescriptprogramming~15 mins

Abstract classes in Typescript - Deep Dive

Choose your learning style9 modes available
Overview - Abstract classes
What is it?
Abstract classes are special classes in TypeScript that cannot be used to create objects directly. They serve as blueprints for other classes, defining methods and properties that child classes must implement or can inherit. This helps organize code by sharing common features while forcing specific details to be defined in subclasses.
Why it matters
Without abstract classes, developers might repeat code or fail to enforce important rules about how certain classes should behave. Abstract classes help keep code clean, consistent, and easier to maintain by guiding how related classes are built. This reduces bugs and confusion in bigger projects where many classes share similar roles.
Where it fits
Before learning abstract classes, you should understand basic classes, inheritance, and interfaces in TypeScript. After mastering abstract classes, you can explore design patterns like Template Method or Factory, which often use abstract classes to structure complex behaviors.
Mental Model
Core Idea
An abstract class is a partially built blueprint that defines common features but requires subclasses to complete the details.
Think of it like...
Think of an abstract class like a recipe template that lists the main steps and ingredients but leaves some steps blank for the cook to fill in with their own style.
Abstract Class
┌─────────────────────────┐
│ AbstractClass           │
│ ────────────────────── │
│ - commonProperty        │
│ + commonMethod()        │
│ # abstractMethod()      │
└─────────┬───────────────┘
          │
          ▼
Subclasses
┌───────────────┐  ┌───────────────┐
│ SubclassA     │  │ SubclassB     │
│ ──────────── │  │ ──────────── │
│ + abstractMethod()│  │ + abstractMethod()│
└───────────────┘  └───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding basic classes
🤔
Concept: Learn what classes are and how they create objects with properties and methods.
In TypeScript, a class is like a blueprint for creating objects. For example: class Animal { name: string; constructor(name: string) { this.name = name; } speak() { console.log(`${this.name} makes a sound.`); } } const dog = new Animal('Dog'); dog.speak(); // Output: Dog makes a sound.
Result
You can create objects from classes and call their methods.
Understanding classes is essential because abstract classes build on this concept by adding rules for subclasses.
2
FoundationIntroduction to inheritance
🤔
Concept: Learn how one class can inherit properties and methods from another.
Inheritance lets a class reuse code from another class. For example: class Dog extends Animal { speak() { console.log(`${this.name} barks.`); } } const dog = new Dog('Buddy'); dog.speak(); // Output: Buddy barks.
Result
Subclass Dog inherits from Animal and can override methods.
Inheritance allows code reuse and customization, which abstract classes rely on to enforce structure.
3
IntermediateDefining abstract classes
🤔
Concept: Learn how to declare an abstract class and abstract methods in TypeScript.
An abstract class uses the keyword 'abstract' and cannot be instantiated directly. It can have abstract methods without implementation: abstract class Vehicle { abstract move(): void; start() { console.log('Starting vehicle'); } } // const v = new Vehicle(); // Error: Cannot create instance of abstract class
Result
You cannot create objects from abstract classes, but you can define shared methods and abstract methods.
Abstract classes enforce that subclasses implement certain methods, ensuring consistent behavior.
4
IntermediateImplementing abstract methods in subclasses
🤔Before reading on: Do you think a subclass can skip implementing an abstract method? Commit to your answer.
Concept: Subclasses must provide concrete implementations for all abstract methods from the abstract class.
Continuing from Vehicle: class Car extends Vehicle { move() { console.log('Car is moving'); } } const car = new Car(); car.start(); // Output: Starting vehicle car.move(); // Output: Car is moving
Result
Subclasses provide the missing details for abstract methods, making the class usable.
Knowing that subclasses must implement abstract methods prevents errors and enforces design contracts.
5
IntermediateMixing concrete and abstract methods
🤔
Concept: Abstract classes can have both implemented (concrete) and unimplemented (abstract) methods.
Example: abstract class Appliance { turnOn() { console.log('Appliance is on'); } abstract operate(): void; } class Washer extends Appliance { operate() { console.log('Washing clothes'); } } const washer = new Washer(); washer.turnOn(); // Output: Appliance is on washer.operate(); // Output: Washing clothes
Result
Concrete methods provide shared behavior, while abstract methods require subclass specifics.
This mix allows code reuse and flexibility, making abstract classes powerful for design.
6
AdvancedAbstract classes vs interfaces
🤔Before reading on: Do you think abstract classes and interfaces are interchangeable? Commit to your answer.
Concept: Understand the differences and when to use abstract classes or interfaces in TypeScript.
Interfaces only declare method signatures without implementation, while abstract classes can provide code. Abstract classes can have fields and constructors; interfaces cannot. Example interface: interface Flyer { fly(): void; } class Bird implements Flyer { fly() { console.log('Bird is flying'); } } Abstract class example: abstract class FlyerBase { abstract fly(): void; land() { console.log('Landing'); } } class Eagle extends FlyerBase { fly() { console.log('Eagle is flying'); } }
Result
Abstract classes provide partial implementation and state; interfaces only define contracts.
Knowing the difference helps choose the right tool for code organization and design.
7
ExpertAbstract classes in design patterns
🤔Before reading on: Can you think how abstract classes help implement design patterns? Commit to your answer.
Concept: Explore how abstract classes enable patterns like Template Method to control algorithm steps.
Template Method pattern uses an abstract class to define the skeleton of an algorithm, leaving some steps abstract: abstract class DataProcessor { process() { this.readData(); this.transformData(); this.saveData(); } abstract readData(): void; abstract transformData(): void; saveData() { console.log('Saving data'); } } class CSVProcessor extends DataProcessor { readData() { console.log('Reading CSV data'); } transformData() { console.log('Transforming CSV data'); } } const processor = new CSVProcessor(); processor.process(); // Output: // Reading CSV data // Transforming CSV data // Saving data
Result
Abstract classes guide complex workflows by enforcing step implementations.
Understanding this pattern reveals the power of abstract classes beyond simple inheritance.
Under the Hood
At runtime, abstract classes are compiled to JavaScript classes but cannot be instantiated directly because TypeScript enforces this restriction during compilation. Abstract methods are placeholders without JavaScript code; subclasses provide the actual implementations. The TypeScript compiler checks that all abstract methods are implemented before allowing object creation, ensuring type safety and design correctness.
Why designed this way?
Abstract classes were introduced to provide a middle ground between interfaces and concrete classes, allowing shared code and enforced contracts. This design helps developers avoid code duplication while ensuring subclasses follow a required structure. Alternatives like interfaces alone lack implementation, and concrete classes lack enforced method implementation, so abstract classes balance flexibility and safety.
┌─────────────────────────────┐
│ AbstractClass (TypeScript)  │
│ ────────────────────────── │
│ - abstractMethod()          │
│ - concreteMethod()          │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Subclass                    │
│ ────────────────────────── │
│ + abstractMethod()          │
│ + concreteMethod() (inherited)│
└─────────────────────────────┘

TypeScript compiler checks implementation before JS output.
JavaScript runtime runs concrete methods normally.
Myth Busters - 4 Common Misconceptions
Quick: Can you create an object directly from an abstract class? Commit to yes or no.
Common Belief:You can create objects from abstract classes just like normal classes.
Tap to reveal reality
Reality:Abstract classes cannot be instantiated directly; trying to do so causes a compile-time error.
Why it matters:Trying to instantiate an abstract class leads to errors and confusion, breaking program flow.
Quick: Do abstract classes force subclasses to implement all methods? Commit to yes or no.
Common Belief:Subclasses can ignore abstract methods if they want.
Tap to reveal reality
Reality:Subclasses must implement all abstract methods or themselves be declared abstract.
Why it matters:Ignoring this causes compile errors and incomplete class implementations.
Quick: Are abstract classes and interfaces exactly the same? Commit to yes or no.
Common Belief:Abstract classes and interfaces are interchangeable and serve the same purpose.
Tap to reveal reality
Reality:Abstract classes can have implementations and state; interfaces only declare method signatures.
Why it matters:Confusing them leads to poor design choices and misuse of language features.
Quick: Can abstract classes have constructors? Commit to yes or no.
Common Belief:Abstract classes cannot have constructors because they can't be instantiated.
Tap to reveal reality
Reality:Abstract classes can have constructors to initialize shared properties for subclasses.
Why it matters:Not knowing this limits how you design base classes and share initialization logic.
Expert Zone
1
Abstract classes can have protected constructors to restrict instantiation only to subclasses, enhancing encapsulation.
2
When multiple inheritance is needed, abstract classes combined with interfaces provide flexible design, since TypeScript supports single class inheritance but multiple interfaces.
3
Abstract classes can define default behavior for some methods while forcing subclasses to override others, enabling partial implementation patterns.
When NOT to use
Avoid abstract classes when you only need to define a contract without implementation; use interfaces instead. Also, if you require multiple inheritance of behavior, consider composition or mixins because TypeScript supports only single inheritance for classes.
Production Patterns
Abstract classes are widely used in frameworks to define base components or services with shared logic, such as Angular's base classes for components. They also enable design patterns like Template Method and Strategy by enforcing method implementation while providing reusable code.
Connections
Interfaces
Abstract classes build on interfaces by adding implementation and state.
Understanding interfaces clarifies why abstract classes exist: to combine contracts with shared code.
Design Patterns
Abstract classes enable patterns like Template Method and Factory Method.
Knowing abstract classes helps grasp how design patterns enforce structure and reuse.
Blueprints in Architecture
Abstract classes are like architectural blueprints that specify essential features but leave details to builders.
Seeing abstract classes as blueprints helps understand their role in guiding consistent construction.
Common Pitfalls
#1Trying to instantiate an abstract class directly.
Wrong approach:abstract class Shape { abstract draw(): void; } const s = new Shape(); // Error: Cannot create instance of abstract class
Correct approach:abstract class Shape { abstract draw(): void; } class Circle extends Shape { draw() { console.log('Drawing circle'); } } const c = new Circle(); // Works fine
Root cause:Misunderstanding that abstract classes are incomplete and meant only as base classes.
#2Subclass missing implementation of abstract methods.
Wrong approach:abstract class Animal { abstract makeSound(): void; } class Dog extends Animal { // forgot to implement makeSound } const d = new Dog(); // Error: Non-abstract class 'Dog' does not implement inherited abstract member 'makeSound'.
Correct approach:abstract class Animal { abstract makeSound(): void; } class Dog extends Animal { makeSound() { console.log('Bark'); } } const d = new Dog(); // Works fine
Root cause:Forgetting that all abstract methods must be implemented or the subclass must also be abstract.
#3Using abstract classes when only a contract is needed.
Wrong approach:abstract class Logger { abstract log(message: string): void; } // No shared code, just method signature
Correct approach:interface Logger { log(message: string): void; } // Use interface for pure contracts
Root cause:Confusing abstract classes with interfaces and overcomplicating design.
Key Takeaways
Abstract classes define partial blueprints that cannot be instantiated directly but guide subclasses to implement required methods.
They allow sharing common code and enforcing method implementation, balancing flexibility and structure in object-oriented design.
Subclasses must implement all abstract methods or be declared abstract themselves, ensuring consistent behavior.
Abstract classes differ from interfaces by allowing method implementations and state, making them suitable for shared logic.
They are essential tools in design patterns and large codebases to organize and maintain complex systems effectively.