Abstract Classes: The Blueprint for Inheritance
Learn how to create robust object-oriented structures using abstract classes in TypeScript. Explore key concepts, syntax, and practical examples to master the art of abstract class implementation and inheritance.
Abstract Class
In TypeScript, abstract classes serve as a foundation for building related classes through inheritance. These classes act as blueprints, defining common properties and methods to be shared by derived classes, while also enforcing specific behaviors through abstract methods.
Key Concepts
- Declaration: We use the
abstract
keyword to define an abstract class. - Inheritance: Other classes, known as derived classes, can inherit from the abstract class.
- Instantiation Restriction: You cannot directly create instances (objects) of an abstract class.
- Abstract Methods: Abstract methods lack implementation within the abstract class itself. Derived classes are obligated to provide concrete implementations for these methods.
Example: Defining an Abstract Class Person
Syntax
abstract class Person {
name: string;
constructor(name: string) {
this.name = name;
}
display(): void {
console.log(this.name);
}
abstract find(name: string): Person; // Abstract method
}
Output
Person is an abstract class.
It has a property 'name' and two methods: 'display' and 'find'.
'display' is a regular method with an implementation for logging the name.
'find' is declared as an abstract method. It defines the method signature but lacks an actual implementation.
Derived Class: Employee Inheriting from Person
Syntax
class Employee extends Person {
empCode: number;
constructor(name: string, code: number) {
super(name); // Call super constructor
this.empCode = code;
}
find(name: string): Person {
// Implement logic to find an employee (e.g., using a database)
return new Employee(name, 123); // Example return value
}
}
Output
Employee extends the Person class, inheriting properties and methods.
The Employee constructor calls the super constructor using super(name) to initialize the inherited name property.
find is implemented in Employee, providing the specific logic for finding an employee.
Key Points
- Abstract classes define the contract (properties and methods) that derived classes must adhere to.
- Derived classes provide concrete implementations for abstract methods inherited from the abstract class.
- Abstract methods enforce consistency in behavior across derived classes.
Using the Abstract Class
While you cannot directly create an instance of Person
, you can create objects of Employee
:
Syntax
let emp: Person = new Employee("Alice", 101); // Allowed, using derived class
emp.display(); // Calls inherited method
// let emp2: Person = new Person("Bob", 102); // Not allowed, cannot create instance of abstract class
Output
Employee instance created with name 'Alice' and empCode 101.
Attempt to create a Person instance directly is not allowed.
Abstract Properties
Abstract classes can also have abstract properties without initializers:
Syntax
abstract class Shape {
abstract area: number;
}
class Square extends Shape {
sideLength: number;
constructor(sideLength: number) {
super();
this.sideLength = sideLength;
}
get area(): number {
return this.sideLength * this.sideLength;
}
}
Output
Shape class has an abstract property 'area'.
Square class implements the 'area' property by calculating the area of a square.
Benefits of Abstract Classes
- Improved Code Reusability: Abstract classes promote code reuse by encapsulating common functionalities.
- Enforced Consistency: Derived classes must implement abstract methods, ensuring consistent behavior.
- Clearer Class Hierarchies: Abstract classes define the relationships between classes.
When to Use Abstract Classes
- When you want to define a common structure and behavior for a group of related classes.
- When you want to enforce specific functionality in derived classes.
- When creating a base class for inheritance hierarchies.
By understanding abstract classes, you can leverage them to create well-structured, reusable, and maintainable object-oriented code in TypeScript.