How to Use Class Inheritance in TypeScript

Use class inheritance in TypeScript when multiple classes should share the same base properties and methods while still adding their own specialized behavior. This is perfect for UI components, domain models, game entities, and service hierarchies.

What you’ll build or solve

You’ll learn how to use class inheritance in TypeScript with extends, super(), and method overriding. You’ll also know when inheritance is cleaner than duplication.

When this approach works best

This approach is the right choice when several classes clearly model an “is-a” relationship.

Common real-world scenarios include:

  • Animal → Dog
  • User → Admin
  • Shape → Circle
  • UI base components
  • Shared API services

This is a bad idea when the relationship is better modeled with composition instead of hierarchy.

Prerequisites

You only need:

  • Basic TypeScript classes
  • Constructors
  • Access modifiers
  • Methods

Step-by-step instructions

Step 1: Create a base class

The parent class holds shared logic.

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

  speak(): string {
    return `${this.name} makes a sound`;
  }
}

This becomes the reusable foundation.

Step 2: Extend the base class

Use extends to inherit properties and methods.

class Dog extends Animal {
  bark(): string {
    return `${this.name} barks`;
  }
}

Now Dog gets both name and speak() automatically.

const dog = new Dog("Rex");
dog.speak();
dog.bark();

Step 3: Use super() in child constructors

When the child has its own constructor, call the parent first.

class Admin extends User {
  constructor(name: string, public role: string) {
    super(name);
  }
}

This initializes the inherited part safely.

Step 4: Override methods when behavior changes

Children can customize inherited methods.

class Cat extends Animal {
  speak(): string {
    return `${this.name} meows`;
  }
}

This replaces the parent version for that subclass.

What to look for:

  • extends creates inheritance
  • super() initializes parent state
  • Children reuse base logic
  • Overriding customizes behavior
  • Great for shared blueprints

Examples you can copy

User → Admin

class Admin extends User {}

Shape → Circle

class Circle extends Shape {}

Base API → Auth API

class AuthApi extends BaseApi {}

Common mistakes and how to fix them

Mistake 1: Forgetting super()

What the reader might do:

Create a child constructor without calling the parent.

Why it breaks: inherited fields are not initialized.

Corrected approach:

Always call super() first.

Mistake 2: Inheriting when composition is better

What the reader might do:

Create deep unrelated class chains.

Why it breaks: the design becomes rigid.

Corrected approach:

Use composition for shared helpers.

Mistake 3: Overriding without matching the contract

What the reader might do:

Change the method return type unexpectedly.

Why it breaks: subclass compatibility weakens.

Corrected approach:

Keep the same method shape.

Troubleshooting

If the child constructor errors, add super().

If shared logic feels unrelated, prefer composition.

If overridden methods behave oddly, verify the signature.

If the hierarchy gets deep, simplify the design.

Quick recap

  • Use extends for inheritance
  • Call super() in child constructors
  • Reuse shared parent logic
  • Override methods when behavior changes
  • Prefer composition for loose relationships