TypeScript Inheritance Tutorial

In this TypeScript tutorial we learn how to inherit functionality from one class to another without rewriting any code.

We also learn how to inherit constructor functionality into child classes with the super() constructor.

What is class inheritance

Inheritance makes it possible to reuse code from other classes.

Developers can wrap common sections of code in one class, then inherit this functionality and reuse that code in a sub, or child class.

The main class is known as the base, parent or super class. The class that inherits code from the parent is known as the sub, or child class.

Inheritance is referred to as an is-a type relationship between classes. For example, a cat is an animal, or a car is a vehicle.

Inheritance also provides us with polymorphic behavior, which can be quite powerful.

note We should compile the following scripts with the compiler flag --target es6 or greater.

How to create a child (sub) class

To create a class that inherits from another, we use the extends keyword.

Syntax:
class ParentClass {}

class ChildClass extends ParentClass {}

When we inherit from a parent class, the child class will receive all the properties and methods that the parent class has.

Example:
class Animal {

  move() {
    console.log("Animal parent class. Move...")
  }
}

class Dog extends Animal {

  growl() {
    console.log("Dog child class. A dog can growl, but a duck can't. Grrr...")
  }
}

class Duck extends Animal {

  quack() {
    console.log("Duck Child class. A duck can quack, but a dog can't. Quack...")
  }
}

var goofy = new Dog()
var donald = new Duck()

// both child classes has access
// to the 'move()' method in the
// parent class
goofy.move()
donald.move()

// as well as their own functionality
goofy.growl()
donald.quack()

In the example above, we create two child classes, Dog and Duck , that inherit from the parent class Animal .

All types of animals can move in some capacity, so it’s included in the parent class. Any child class that inherits from animal, will have the move functionality available to it.

Child classes have more specific functionality that won’t make sense in the parent class. An example would be growling, because not all animals can growl.

As another example, consider an online forum. Users of the forum typically have different roles, such as member, moderator and administrator.

  • A member, moderator and administrator may create posts.
  • A moderator and administrator may move posts to other categories, but a member can’t.
  • An administrator may create categories, but a moderator and member can’t.

So, the parent class could include the functionality to create posts, so as to be available to all roles. Child classes would be used to add functionality for different roles.

How to inherit constructor functionality with super

If a child class doesn’t have its own constructor, we can use the constructor of the parent class as we normally would.

Example:
class Animal {
  name: string

  constructor(name: string) {
    this.name = name
  }
}

class Dog extends Animal {

  growl() {
    console.log("Dog child class. A dog can growl, but a duck can't. Grrr...")
  }
}

var dog1 = new Dog("Pluto")

console.log("Goofy's dog's name is " + dog1.name)

But, when a child class has its own constructor, we need to add the functionality from the parent class constructor, into the child class constructor.

Example:
class Animal {
  name: string

  constructor(name: string) {
    this.name = name
  }
}

class Dog extends Animal {
  isGoodBoy: boolean

  constructor(isGoodBoy: boolean) {
    this.isGoodBoy = isGoodBoy
  }

  growl() {

    if (this.isGoodBoy) {
      console.log(name + " doesn't growl, he's a good boy")
    } else {
      console.log("Grrrrr....")
    }
  }
}

var dog1 = new Dog("Pluto")

console.log("Goofy's dog's name is " + dog1.name)

In the example above, we’ve added a constructor in the child class. We then try to access the name property from the parent class again, but this time the compiler raises an error.

Output:
main.ts:14:3 - error TS2377: Constructors for derived classes must contain a 'super' call.

14   constructor(isGoodBoy) {
     ~~~~~~~~~~~~~~~~~~~~~~~~
15

16     this.isGoodBoy = isGoodBoy;
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17   }
   ~~~

main.ts:16:5 - error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.

16     this.isGoodBoy = isGoodBoy;
       ~~~~

The error means we have to bring everything from the parent constructor into the child constructor before we can access it. We do this with super() .

We can think of super as a regular function call, with super being the function name. It also uses all the parameters of the parent class constructor.

Example:
class Animal {
  name: string

  constructor(name: string) {
    this.name = name
  }
}

class Dog extends Animal {
  isGoodBoy: boolean

  constructor(name: string, isGoodBoy: boolean) {
    super(name);
    this.isGoodBoy = isGoodBoy;
  }

  growl() {
    if (this.isGoodBoy) {
      console.log(name + " doesn't growl, he's a good boy")
    } else {
      console.log("Grrrrr....")
    }
  }
}

var dog1 = new Dog("Pluto", true)

console.log("Goofy's dog's name is " + dog1.name)

We call super() in the child class’s constructor. Because the parent class has a parameter (name), super also needs the parameter so we add it to both super and the constructor parameter list.

Summary: Points to remember

  • Inheritance allows one class to inherit functionality from another without rewriting the same code.
  • We use the extends keyword to indicate that one class inherits from another.
  • The child class will automatically receive all the functionality from the parent class unless it contains its own constructor.
  • We inherit constructor functionality with the super() constructor.
    • If the parent class constructor has any parameters, the super() constructor will need the same parameters.