TypeScript - 繼承

Hello, future programmers! Today, we're going to embark on an exciting journey into the world of TypeScript inheritance. As your friendly neighborhood computer teacher, I'm here to guide you through this fascinating topic. So, grab your virtual backpacks, and let's dive in!

TypeScript - Inheritance

What is Inheritance?

Before we start, let's understand what inheritance actually means. Imagine you're creating a family tree. Each new generation inherits certain traits from their parents. In programming, inheritance works similarly. It allows a new class to be based on an existing class, inheriting its properties and methods. Cool, right?

Single Class Inheritance

Let's start with the simplest form of inheritance: single class inheritance. This is when one class (child class) inherits from another class (parent class).

Basic Example

class Animal {
name: string;

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

makeSound(): void {
console.log("Some generic animal sound");
}
}

class Dog extends Animal {
breed: string;

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

makeSound(): void {
console.log("Woof! Woof!");
}
}

let myDog = new Dog("Buddy", "Golden Retriever");
console.log(myDog.name);  // Output: Buddy
console.log(myDog.breed); // Output: Golden Retriever
myDog.makeSound();        // Output: Woof! Woof!

In this example, Dog is inheriting from Animal. The extends keyword is used to create a class that is a child of another class.

Explanation

  1. We define a base Animal class with a name property and a makeSound method.
  2. We then create a Dog class that extends Animal.
  3. The Dog class has its own breed property.
  4. We use the super keyword in the Dog constructor to call the Animal constructor.
  5. We override the makeSound method in the Dog class.

Super Keyword

You might have noticed the super keyword in our previous example. Let's dive deeper into what it does.

Example with Super

class Vehicle {
make: string;
model: string;

constructor(make: string, model: string) {
this.make = make;
this.model = model;
}

getInfo(): string {
return `${this.make} ${this.model}`;
}
}

class Car extends Vehicle {
numDoors: number;

constructor(make: string, model: string, numDoors: number) {
super(make, model);
this.numDoors = numDoors;
}

getInfo(): string {
return `${super.getInfo()} with ${this.numDoors} doors`;
}
}

let myCar = new Car("Toyota", "Corolla", 4);
console.log(myCar.getInfo()); // Output: Toyota Corolla with 4 doors

Explanation

  1. The super keyword is used in the Car constructor to call the Vehicle constructor.
  2. In the getInfo method of Car, we use super.getInfo() to call the getInfo method of the parent class.

The super keyword allows us to access and call functions on an object's parent.

Method Overriding

Method overriding occurs when a child class provides a specific implementation of a method that is already defined in its parent class. We've actually seen this in both our previous examples!

Another Example of Method Overriding

class Shape {
getArea(): number {
return 0;
}
}

class Circle extends Shape {
radius: number;

constructor(radius: number) {
super();
this.radius = radius;
}

getArea(): number {
return Math.PI * this.radius * this.radius;
}
}

class Rectangle extends Shape {
width: number;
height: number;

constructor(width: number, height: number) {
super();
this.width = width;
this.height = height;
}

getArea(): number {
return this.width * this.height;
}
}

let myCircle = new Circle(5);
console.log(myCircle.getArea()); // Output: 78.53981633974483

let myRectangle = new Rectangle(4, 5);
console.log(myRectangle.getArea()); // Output: 20

Explanation

  1. We have a base Shape class with a getArea method that returns 0.
  2. Both Circle and Rectangle classes extend Shape and override the getArea method with their own implementations.
  3. The Circle class calculates the area using the formula πr².
  4. The Rectangle class calculates the area by multiplying width and height.

Multilevel Inheritance

Multilevel inheritance involves a child class inheriting from another child class. It's like a family tree with multiple generations.

Multilevel Inheritance Example

class Grandparent {
surname: string;

constructor(surname: string) {
this.surname = surname;
}

getSurname(): string {
return this.surname;
}
}

class Parent extends Grandparent {
firstName: string;

constructor(firstName: string, surname: string) {
super(surname);
this.firstName = firstName;
}

getFullName(): string {
return `${this.firstName} ${this.getSurname()}`;
}
}

class Child extends Parent {
middleName: string;

constructor(firstName: string, middleName: string, surname: string) {
super(firstName, surname);
this.middleName = middleName;
}

getFullName(): string {
return `${this.firstName} ${this.middleName} ${this.getSurname()}`;
}
}

let myChild = new Child("John", "Doe", "Smith");
console.log(myChild.getFullName()); // Output: John Doe Smith

Explanation

  1. We have a Grandparent class with a surname property.
  2. The Parent class extends Grandparent and adds a firstName property.
  3. The Child class extends Parent and adds a middleName property.
  4. Each class has its own implementation of getFullName method.

Summary of Inheritance Methods

Here's a table summarizing the key methods and keywords we've discussed:

Method/Keyword Description
extends Used to create a class as a child of another class
super() Calls the constructor of the parent class
super.method() Calls a method from the parent class
Method Overriding Providing a new implementation for a method in a child class

And there you have it! We've covered the basics of inheritance in TypeScript. Remember, practice makes perfect, so don't hesitate to experiment with these concepts. Happy coding, future TypeScript wizards!

Credits: Image by storyset