Multiple Inheritance in TypeScript
- Single Inheritance in TypeScript
- Multiple Inheritance With TypeScript Classes
- Multiple Inheritance With TypeScript Interfaces
- Multiple Inheritance With TypeScript Mixins
There are several programming paradigms have evolved over the years. Object-Oriented Programming(OOP) is one of the main paradigms based on real-world entities and their interaction.
Inheritance is one of the well-known OOP concepts that allows acquiring the parent entity’s properties and behaviors by sub-entities.
Single Inheritance in TypeScript
TypeScript supports OOP techniques up to some extent. It supports inheriting from one parent entity, allowing programmers to reuse their code effectively.
We can inherit from a parent entity using the extends
keyword, as shown in the following.
class Animal {
constructor() {
console.log("Animal class");
}
}
class Cat extends Animal {
constructor() {
super();
}
}
const cat = new Cat();
Output:
"Animal class"
This is called single inheritance which the given class can extend to only one parent class.
Multiple Inheritance With TypeScript Classes
It is possible to acquire properties and behaviors from more than one parent entity in Java-like languages. This is called multiple inheritance.
TypeScript does not support multiple inheritance.
Let’s try to extend multiple parent classes in TypeScript using extends
.
class Engineer {
constructor() {
console.log("Employee class");
}
}
class Person {
constructor() {
console.log("Person class");
}
}
class Employee extends Engineer, Person {
}
Then, let’s transpile the TypeScript code, as shown in the following.
tsc example1.ts
Output:
As expected, it gives an error that TypeScript only allows extending a single class.
Multiple Inheritance With TypeScript Interfaces
TypeScript interfaces support multiple inheritance out of the box. They can extend more than one class.
Let’s create two classes, Person
and Engineer
, and add some dummy methods.
class Person {
name: string;
constructor() {
console.log("Person class");
}
sayImAPerson(){
console.log("Hey, I am a person");
}
}
class Engineer {
salary: number;
constructor() {
console.log("Engineer class");
}
sayImAnEngineer(){
console.log("I am an engineer too");
}
}
Next, we will be creating a new type or class to extend the above two classes.
class Employee {
empId: string;
}
Since the Employee
class cannot extend more than one parent class, we should use an interface with the same name Employee
to use TypeScript declaration merging. In this way, you can merge interfaces and classes.
Let’s create the Employee
interface, which extends the Person
and Engineer
classes, as shown in the following.
interface Employee extends Person, Engineer {
}
Let’s transpile the TypeScript code and check whether we get any errors.
Output:
As expected, there are no errors when using extends
with more than one parent class inside the interface declaration. Hence, the interface supports multiple inheritances.
But there is still a problem if we call a method inside the inherited class. We do not have access to the method implementations.
Let’s try calling the sayImAnEngineer()
method.
let emp: Employee = new Employee;
emp.sayImAnEngineer();
We should transpile the code first; it won’t give any error. Then, try running the generated JavaScript; it would raise an error, as shown in the following output.
Output:
TypeScript couldn’t locate the sayImAnEngineer
method. We can overcome this by using TypeScript mixins
.
Multiple Inheritance With TypeScript Mixins
TypeScript mixins mechanism can copy all the methods available in the parent classes to the derived class or sub-class. The mixin creation method should go through all the properties in the parent classes and retrieve the content.
Then, it should set all the content in the derived class as it is. There is a method provided by the official TypeScript documentation: mixin creation method.
It is recommended to use within your TypeScript file, as shown in the following.
function applyMixins(derivedCtor: any, constructors: any[]) {
constructors.forEach((baseCtor) => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
Object.defineProperty(
derivedCtor.prototype,
name,
Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
Object.create(null)
);
});
});
}
Let’s include the applyMixins
method inside our TypeScript example.
class Person {
name: string;
constructor() {
console.log("Person class");
}
sayImAPerson(){
console.log("Hey, I am a person");
}
}
class Engineer {
salary: number;
constructor() {
console.log("Engineer class");
}
sayImAnEngineer(){
console.log("I am an engineer too");
}
}
class Employee {
empId: string;
}
interface Employee extends Person, Engineer {
}
function applyMixins(derivedCtor: any, constructors: any[]) {
constructors.forEach((baseCtor) => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
Object.defineProperty(
derivedCtor.prototype,
name,
Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
Object.create(null)
);
});
});
}
Now, let’s call the applyMixins
method, as shown in the following.
applyMixins(Employee, [Person, Engineer]);
The first parameter should be the derived class; in this case, it is the Employee
class. The next parameter is an array that contains all the parent classes the derived class would extend.
Finally, let’s create an Employee
object and call the sayImAnEngineer
method from the Engineer
parent class.
let emp: Employee = new Employee;
emp.sayImAnEngineer();
Output:
There are no errors this time; it means the mixins technique worked. In this way, you can implement the multiple inheritances in TypeScript.
Nimesha is a Full-stack Software Engineer for more than five years, he loves technology, as technology has the power to solve our many problems within just a minute. He have been contributing to various projects over the last 5+ years and working with almost all the so-called 03 tiers(DB, M-Tier, and Client). Recently, he has started working with DevOps technologies such as Azure administration, Kubernetes, Terraform automation, and Bash scripting as well.