Lessons

TypeScript Tutorial

TypeScript Control Structures

TypeScript Function Types

TypScript Classes

TypeScript Abstract Class

Introduction to TypeScript Abstract Classes

In object-oriented programming, abstract classes are used to define common characteristics for related classes. They cannot be instantiated directly; instead, they provide a base from which other classes can inherit. This approach promotes code reusability and establishes a clear contract for derived classes to follow.

What is TypeScript Abstract Class?

An abstract class in TypeScript is a class that cannot be instantiated on its own and is intended to be extended by other classes. It can include both implemented methods and abstract methods. Abstract methods are declared without an implementation and must be defined in any non-abstract subclass. This mechanism enforces a consistent interface across all subclasses, ensuring that certain methods are implemented uniformly.

Example:

tsx
1
2
3
4
5
6
abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('The animal moves.');
    }
}

In this example, Animal is an abstract class with an abstract method makeSound() and a regular method move(). Any class that extends Animal must implement the makeSound() method.

How to Define Abstract Class in TypeScript

To define an abstract class in TypeScript, use the abstract keyword before the class declaration. Similarly, abstract methods within the class are also prefixed with the abstract keyword. It's important to note that abstract methods do not have a body; they only define the method signature.

Syntax:

tsx
1
2
3
4
abstract class ClassName {
    abstract methodName(parameters): returnType;
    // Other methods and properties
}

Example:

tsx
1
2
3
4
5
6
7
8
9
abstract class Vehicle {
    constructor(public make: string, public model: string) {}

    abstract startEngine(): void;

    displayInfo(): void {
        console.log(`Vehicle: ${this.make} ${this.model}`);
    }
}

Here, Vehicle is an abstract class with an abstract method startEngine() and a concrete method displayInfo(). Any subclass of Vehicle must provide an implementation for startEngine().

What are the uses of TypeScript Abstract Classes

Abstract classes are primarily used as base classes from which other classes derive. They allow you to define methods that must be implemented in any subclass, ensuring a consistent interface. Additionally, abstract classes can include concrete methods that provide common functionality to all derived classes.

Example:

tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
abstract class Employee {
    constructor(public name: string) {}

    abstract calculateSalary(): number;

    getDetails(): void {
        console.log(`Employee Name: ${this.name}`);
    }
}

class FullTimeEmployee extends Employee {
    constructor(name: string, public annualSalary: number) {
        super(name);
    }

    calculateSalary(): number {
        return this.annualSalary;
    }
}

class PartTimeEmployee extends Employee {
    constructor(name: string, public hourlyRate: number, public hoursWorked: number) {
        super(name);
    }

    calculateSalary(): number {
        return this.hourlyRate * this.hoursWorked;
    }
}

const fullTimeEmp = new FullTimeEmployee('Alice', 60000);
fullTimeEmp.getDetails(); // Output: Employee Name: Alice
console.log(fullTimeEmp.calculateSalary()); // Output: 60000

const partTimeEmp = new PartTimeEmployee('Bob', 50, 120);
partTimeEmp.getDetails(); // Output: Employee Name: Bob
console.log(partTimeEmp.calculateSalary()); // Output: 6000

In this example, Employee is an abstract class with an abstract method calculateSalary() and a concrete method getDetails(). Both FullTimeEmployee and PartTimeEmployee classes extend Employee and provide their own implementations of calculateSalary().

Advanced uses of Abstract Methods

Abstract methods in an abstract class define a contract that derived classes must fulfill. This is particularly useful when you want to ensure that all subclasses implement specific functionality, but the implementation may vary between subclasses.

Example:

tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
abstract class Shape {
    abstract area(): number;
    abstract perimeter(): number;

    describe(): void {
        console.log(`Area: ${this.area()} sq.units`);
        console.log(`Perimeter: ${this.perimeter()} units`);
    }
}

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

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

    perimeter(): number {
        return 2 * (this.width + this.height);
    }
}

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

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

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

const rect = new Rectangle(10, 5);
rect.describe();
// Output:
// Area: 50 sq.units
// Perimeter: 30 units

const circ = new Circle(7);
circ.describe();
// Output:
// Area: 153.93804002589985 sq.units
// Perimeter: 43.982297150257104 units

In this example, the abstract class Shape defines two abstract methods: area() and perimeter(). The Rectangle and Circle classes extend Shape and provide their specific implementations for these methods. The describe() method in the Shape class is a concrete method that calls the abstract methods to display the area and perimeter. This demonstrates how abstract methods enforce consistency while allowing subclasses to tailor implementations based on specific requirements.

Conclusion

Abstract classes in TypeScript are important feature for building structured and maintainable object-oriented programs. By defining common behaviors, enforcing consistent interfaces, and supporting polymorphism, abstract classes enable developers to create scalable and efficient codebases.

Key Takeaways

  1. Blueprints for Derived Classes: Abstract classes serve as a template for subclasses, ensuring consistent implementation.
  2. Code Reusability: Shared logic can be defined once in the abstract class and reused across multiple subclasses.
  3. Improved Readability: They provide clear and structured hierarchies that make the code easier to understand.
  4. Polymorphism Support: Abstract classes enable generic programming by allowing operations on base class references.

Frequently Asked Questions