Welcome back to our exploration of Object-Oriented Programming (OOP) in TypeScript. This unit's topic is Inheritance, a feature that can significantly enhance code reusability and efficiency.
Programming, especially OOP, often mirrors concepts found in the real world. Inheritance is one such trait - Child
classes inherit characteristics from their Parent
classes, akin to genetics in biology.
Here is a concrete TypeScript demonstration of a Child
class inheriting from a Parent
class:
TypeScript1// Parent class 2class Parent { 3 name: string; // name property 4 5 constructor(name: string) { 6 this.name = name; 7 } 8 9 greet(): void { 10 console.log(`Hello, my name is ${this.name}`); // greet method 11 } 12} 13 14// 'Child' class extending 'Parent' 15class Child extends Parent { 16 age: number; // age property 17 18 constructor(name: string, age: number) { 19 super(name); 20 this.age = age; 21 } 22 23 info(): void { 24 console.log(`I am ${this.age} years old.`); // info method 25 } 26} 27 28const child = new Child('Alice', 10); 29child.greet(); // prints: Hello, my name is Alice 30child.info(); // prints: I am 10 years old.
In this instance, the Child
class inherits from the Parent
class, thereby sharing the greet()
method. This is inheritance in action!
We introduce the keyword extends
for implementing inheritance. It's a potent keyword that allows a new class to inherit properties and methods from an existing class. In short, a Child class extends
from a Parent class.
For example, a Car
extends a Vehicle
. While both have the potential for movement, a Car
has additional specific attributes — such as the number of wheels.
TypeScript1// Vehicle class 2class Vehicle { 3 name: string; // name property 4 speed: number; // speed property 5 6 constructor(name: string, speed: number) { 7 this.name = name; 8 this.speed = speed; 9 } 10 11 move(): void { 12 console.log(`${this.name} moves at ${this.speed} mph.`); // move method 13 } 14} 15 16// 'Car' class extending 'Vehicle' 17class Car extends Vehicle { 18 wheels: number; // new wheels property 19 20 constructor(name: string, speed: number, wheels: number) { 21 super(name, speed); // call to parent constructor 22 this.wheels = wheels; 23 } 24 25 specs(): void { 26 console.log(`I am a ${this.name} and I have ${this.wheels} wheels.`); // specs method 27 } 28} 29 30const myCar = new Car('Toyota', 120, 4); 31myCar.move(); // prints: Toyota moves at 120 mph 32myCar.specs(); // prints: I am a Toyota and I have 4 wheels.
In this demonstration, the Car
class extends the Vehicle
class, adopting the move()
method.
The factor that unites the parent and child class is the super
keyword. It calls the constructor of the parent class to enable the inheritance of its properties and methods. A real-world parallel would be an apple, a variety of fruit, inheriting from its parent category Fruit.
TypeScript1class Fruit { 2 name: string; // name property 3 4 constructor(name: string) { 5 this.name = name; 6 console.log(`Fruit's constructor called with name=${name}`); 7 } 8 9 printName(): void { 10 console.log(`Fruit's name: ${this.name}`); 11 } 12} 13 14class Apple extends Fruit { 15 color: string; // color property 16 17 constructor(name: string, color: string) { 18 super(name); // calling parent class constructor 19 this.color = color; 20 console.log(`Apple's constructor called with name=${name}, color=${color}`); 21 } 22 23 printColor(): void { 24 console.log(`Color of ${this.name} is ${this.color}`); 25 } 26} 27 28let apple = new Apple('Apple', 'Red'); 29// Prints: 30// Fruit's constructor called with name=Apple 31// Apple's constructor called with name=Apple, color=Red 32 33apple.printName(); // Prints: Fruit's name: Apple 34apple.printColor(); // Prints: Color of Apple is Red
In the Apple
class above, super
calls the constructor of the Fruit
class, inheriting the name
property and the printName()
method. If the Apple
class didn't have any constructor, TypeScript would automatically call the parent's constructor when creating an instance of the Apple
class.
Occasionally during inheritance, a Child
class might require a different method behavior than its Parent
class. This is where method redefinition, or method overriding, comes into the picture.
Method overriding enables a Child
class to offer a different implementation of methods that are already defined in its Parent
class. Using the same method name and parameters in the Child
class, the Parent
class's method can be overridden.
Here's a practical example:
TypeScript1class Parent { 2 greet(): void { 3 console.log('Hello from Parent'); 4 } 5} 6 7class Child extends Parent { 8 // Method override 9 greet(): void { 10 console.log('Hello from Child'); 11 } 12} 13 14const child = new Child(); 15child.greet(); // prints: Hello from Child
In this script, the Child
class overrides the Parent
class's greet()
. When we invoke greet()
on a Child
instance, the Child
class message is printed, not the Parent
's.
It's OOP's flexibility allowing us to tailor classes to meet their intended purpose. Handle it with care — respect the intended use of inherited methods and ensure your updated method is suitable for your class's needs!
Great work! Today, we've covered and understood inheritance in TypeScript, explored how properties and methods traverse from a parent class to a child class via extends
, and identified how super
initiates a connection between a child class and its parent class.
The next step is effective practice sessions, where you'll create classes related to real-world scenarios. And remember, practice is the key to mastery! Stay motivated, and continue building your coding prowess!