TypeScript Inheritance

Extending classes to create specialized versions

🌳 What is Inheritance?

Inheritance allows a class to inherit properties and methods from another class. The child class gets all features from the parent class and can add its own unique features, promoting code reuse and organization.


// Parent class
class Animal {
    name: string;
    
    constructor(name: string) {
        this.name = name;
    }
    
    move() {
        return `${this.name} is moving`;
    }
}

// Child class
class Dog extends Animal {
    bark() {
        return `${this.name} says Woof!`;
    }
}

const dog = new Dog("Buddy");
console.log(dog.move());
console.log(dog.bark());
                                    

Output:

Buddy is moving

Buddy says Woof!

Inheritance Concepts

👨‍👦

Parent Class

Base class with common features

class Vehicle {
    brand: string;
    start() {}
}
👶

Child Class

Inherits from parent class

class Car extends Vehicle {
    doors: number;
}
🔄

Method Override

Replace parent methods

class Cat extends Animal {
    move() {
        return "Cat sneaks";
    }
}
⬆️

Super Keyword

Access parent class members

constructor() {
    super();
}

🔹 Basic Inheritance

Create a child class that extends a parent class:

class Person {
    constructor(
        public name: string,
        public age: number
    ) {}

    introduce() {
        return `Hi, I'm ${this.name} and I'm ${this.age} years old`;
    }
}

class Student extends Person {
    constructor(
        name: string,
        age: number,
        public grade: number
    ) {
        super(name, age); // Call parent constructor
    }

    study() {
        return `${this.name} is studying`;
    }
}

const student = new Student("Alice", 20, 12);
console.log(student.introduce()); // Inherited method
console.log(student.study());     // Own method

Output:

Hi, I'm Alice and I'm 20 years old

Alice is studying

🔹 Method Overriding

Child classes can override parent methods with their own implementation:

class Shape {
    constructor(public name: string) {}

    getArea(): number {
        return 0;
    }

    describe() {
        return `This is a ${this.name}`;
    }
}

class Circle extends Shape {
    constructor(public radius: number) {
        super("Circle");
    }

    // Override parent method
    getArea(): number {
        return Math.PI * this.radius * this.radius;
    }
}

class Rectangle extends Shape {
    constructor(
        public width: number,
        public height: number
    ) {
        super("Rectangle");
    }

    // Override parent method
    getArea(): number {
        return this.width * this.height;
    }
}

const circle = new Circle(5);
const rect = new Rectangle(4, 6);

console.log(circle.describe());
console.log(`Circle area: ${circle.getArea().toFixed(2)}`);
console.log(`Rectangle area: ${rect.getArea()}`);

Output:

This is a Circle

Circle area: 78.54

Rectangle area: 24

🔹 Using Super Keyword

Access parent class methods and properties using 'super':

class Employee {
    constructor(
        public name: string,
        public salary: number
    ) {}

    getDetails() {
        return `${this.name}: $${this.salary}`;
    }

    getAnnualSalary() {
        return this.salary * 12;
    }
}

class Manager extends Employee {
    constructor(
        name: string,
        salary: number,
        public teamSize: number
    ) {
        super(name, salary);
    }

    // Override and extend parent method
    getDetails() {
        const baseDetails = super.getDetails(); // Call parent method
        return `${baseDetails}, Team: ${this.teamSize} people`;
    }

    getBonus() {
        return super.getAnnualSalary() * 0.1; // Use parent method
    }
}

const manager = new Manager("Sarah", 8000, 5);
console.log(manager.getDetails());
console.log(`Annual salary: $${manager.getAnnualSalary()}`);
console.log(`Bonus: $${manager.getBonus()}`);

Output:

Sarah: $8000, Team: 5 people

Annual salary: $96000

Bonus: $9600

🔹 Protected Members

Protected members are accessible in the class and its subclasses:

class BankAccount {
    protected balance: number = 0;

    constructor(public accountNumber: string) {}

    deposit(amount: number) {
        this.balance += amount;
    }

    getBalance() {
        return this.balance;
    }
}

class SavingsAccount extends BankAccount {
    private interestRate: number = 0.05;

    addInterest() {
        // Can access protected balance from parent
        const interest = this.balance * this.interestRate;
        this.balance += interest;
        return interest;
    }

    getAccountInfo() {
        return `Account ${this.accountNumber}: $${this.balance}`;
    }
}

const savings = new SavingsAccount("SAV-001");
savings.deposit(1000);
console.log(`Interest earned: $${savings.addInterest()}`);
console.log(savings.getAccountInfo());

Output:

Interest earned: $50

Account SAV-001: $1050

🔹 Multi-Level Inheritance

Classes can inherit from other derived classes:

class LivingBeing {
    breathe() {
        return "Breathing...";
    }
}

class Animal extends LivingBeing {
    constructor(public name: string) {
        super();
    }

    eat() {
        return `${this.name} is eating`;
    }
}

class Dog extends Animal {
    constructor(name: string, public breed: string) {
        super(name);
    }

    bark() {
        return `${this.name} the ${this.breed} says Woof!`;
    }
}

const dog = new Dog("Max", "Golden Retriever");
console.log(dog.breathe()); // From LivingBeing
console.log(dog.eat());     // From Animal
console.log(dog.bark());    // From Dog

Output:

Breathing...

Max is eating

Max the Golden Retriever says Woof!

🧠 Test Your Knowledge

Which keyword is used to inherit from a parent class?