Table of Contents
- Introduction
- What is Inheritance in TypeScript?
- Single Inheritance in TypeScript
- Extending Classes
- Overriding Methods
- The
super
Keyword in Inheritance - Multiple Inheritance (Simulated through Interfaces)
- Class Hierarchies: Building Relationships Between Classes
- Abstract Classes and Their Role in Inheritance
- Constructor Inheritance and Initialization
- Conclusion
Introduction
Inheritance is one of the core concepts of object-oriented programming (OOP) that allows a class to inherit properties and methods from another class. In TypeScript, inheritance helps create hierarchical relationships between classes, making it possible to reuse and extend existing code. TypeScript builds upon JavaScript’s prototypal inheritance by introducing features such as access modifiers, abstract classes, and interfaces to provide a more structured approach to inheritance.
In this article, we will dive deep into inheritance and class hierarchies in TypeScript, explaining how inheritance works, how to extend classes, override methods, and simulate multiple inheritance. We will also discuss the role of abstract classes and how to implement constructor inheritance.
What is Inheritance in TypeScript?
Inheritance is a mechanism where a new class (called a subclass or child class) derives properties and methods from an existing class (called a superclass or parent class). The subclass can inherit the behavior of the parent class and also define additional properties or override the inherited methods.
In TypeScript, inheritance is achieved using the extends
keyword. A child class can extend a parent class, gaining access to its public and protected members.
Example of Inheritance
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak(): void {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name: string) {
super(name); // Calls the constructor of the parent class
}
speak(): void {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog("Buddy");
dog.speak(); // Output: Buddy barks.
In this example:
- The
Dog
class extends theAnimal
class. - The
Dog
class inherits thename
property andspeak()
method fromAnimal
. - The
Dog
class overrides thespeak()
method to provide a custom implementation for dogs.
Single Inheritance in TypeScript
TypeScript supports single inheritance, where a class can only inherit from one parent class. However, TypeScript allows you to simulate multiple inheritance through interfaces, which we’ll cover later.
Extending Classes
When a class extends another, it inherits the properties and methods of the parent class. However, it cannot inherit private members of the parent class. Only public and protected members are accessible in the child class.
Example of Extending a Class
class Person {
protected name: string;
constructor(name: string) {
this.name = name;
}
greet(): void {
console.log(`Hello, ${this.name}!`);
}
}
class Employee extends Person {
private jobTitle: string;
constructor(name: string, jobTitle: string) {
super(name); // Calls the constructor of Person
this.jobTitle = jobTitle;
}
displayJobTitle(): void {
console.log(`${this.name} is a(n) ${this.jobTitle}.`);
}
}
const employee = new Employee("John", "Software Engineer");
employee.greet(); // Output: Hello, John!
employee.displayJobTitle(); // Output: John is a(n) Software Engineer.
Here:
- The
Employee
class extendsPerson
and inherits thename
property andgreet()
method. - The
Employee
class introduces a new method,displayJobTitle()
, and a privatejobTitle
property. - The
super()
function is used in theEmployee
constructor to call the parent class’s constructor.
The super
Keyword in Inheritance
The super
keyword plays a critical role in class inheritance. It allows you to access the parent class’s methods and properties, as well as call its constructor.
Using super
in Constructor
In the example above, the super(name)
call inside the Employee
class constructor is used to invoke the Person
class’s constructor, ensuring the name
property is correctly initialized.
Using super
to Call Methods
You can also use super
to call methods defined in the parent class. This is useful when you want to override a method but still keep the behavior from the parent class.
Example of Using super
to Call Methods
class Animal {
sound(): void {
console.log("Animal makes a sound");
}
}
class Dog extends Animal {
sound(): void {
super.sound(); // Call the parent class's method
console.log("Dog barks");
}
}
const dog = new Dog();
dog.sound(); // Output: Animal makes a sound \n Dog barks
In this example:
- The
Dog
class overrides thesound()
method but calls the parent class’ssound()
method usingsuper
.
Multiple Inheritance (Simulated through Interfaces)
TypeScript does not support multiple inheritance of classes. A class can only extend one parent class. However, TypeScript allows you to achieve multiple inheritance through interfaces.
A class can implement multiple interfaces, inheriting the contract of each interface. This is how TypeScript simulates multiple inheritance.
Example of Multiple Inheritance Using Interfaces
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
class Duck implements Flyable, Swimmable {
fly(): void {
console.log("Duck is flying");
}
swim(): void {
console.log("Duck is swimming");
}
}
const duck = new Duck();
duck.fly(); // Output: Duck is flying
duck.swim(); // Output: Duck is swimming
In this example:
- The
Duck
class implements two interfaces:Flyable
andSwimmable
. - This allows the
Duck
class to have bothfly()
andswim()
methods.
Class Hierarchies: Building Relationships Between Classes
Class hierarchies allow you to establish relationships between classes. This is useful when you have a base class that contains common functionality, and derived classes that add or modify specific behavior.
Example of Class Hierarchy
class Vehicle {
move(): void {
console.log("Vehicle is moving");
}
}
class Car extends Vehicle {
move(): void {
console.log("Car is driving");
}
}
class Bike extends Vehicle {
move(): void {
console.log("Bike is cycling");
}
}
const car = new Car();
const bike = new Bike();
car.move(); // Output: Car is driving
bike.move(); // Output: Bike is cycling
In this example:
Vehicle
is the base class, andCar
andBike
are subclasses that extendVehicle
.- Each subclass provides its own implementation of the
move()
method, creating a polymorphic behavior.
Abstract Classes and Their Role in Inheritance
An abstract class is a class that cannot be instantiated directly. It can be extended by other classes, which must implement its abstract methods. Abstract classes allow you to define methods that must be implemented by subclasses, ensuring that certain functionality is always provided.
Example of Abstract Class
abstract class Shape {
abstract area(): number;
}
class Circle extends Shape {
radius: number;
constructor(radius: number) {
super();
this.radius = radius;
}
area(): number {
return Math.PI * this.radius ** 2;
}
}
const circle = new Circle(5);
console.log(circle.area()); // Output: 78.53981633974483
In this example:
Shape
is an abstract class with an abstractarea()
method.Circle
extendsShape
and implements thearea()
method.
You cannot create an instance of the Shape
class directly; it must be subclassed and the abstract methods implemented.
Constructor Inheritance and Initialization
When a subclass extends a parent class, the subclass inherits the constructor of the parent class. However, if the parent class’s constructor requires arguments, the subclass must call the parent constructor using the super()
keyword.
Example of Constructor Inheritance
class Animal {
constructor(public name: string) {}
speak(): void {
console.log(`${this.name} speaks.`);
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // Calls the parent class's constructor
}
speak(): void {
console.log(`${this.name} the ${this.breed} barks.`);
}
}
const dog = new Dog("Buddy", "Golden Retriever");
dog.speak(); // Output: Buddy the Golden Retriever barks.
In this example:
- The
Dog
class extendsAnimal
and calls theAnimal
constructor usingsuper(name)
. - The
Dog
class adds an additional propertybreed
and overrides thespeak()
method.
Conclusion
Inheritance is a cornerstone of object-oriented programming, and TypeScript’s class system provides a powerful way to implement it. By using the extends
keyword, TypeScript allows you to create hierarchies where child classes can inherit functionality from parent classes. You can also use abstract classes and interfaces to define reusable structures and enforce implementation contracts across your codebase.
With the ability to simulate multiple inheritance via interfaces and leveraging the super
keyword for calling parent methods and constructors, TypeScript provides a robust model for building complex class hierarchies.