Abstract vs Interface vs Ordinary
When working with TypeScript, there are three primary concepts that can be used to define custom types: abstract classes, interfaces, and ordinary classes. Each of these features has its purpose and use cases, so understanding their differences is essential for writing effective and maintainable code.
Abstract Classes
An abstract class serves as a blueprint for other classes and cannot be instantiated itself. It can contain both implemented and abstract methods, allowing derived classes to either inherit or implement them.
Here’s an example of an abstract class in TypeScript:
abstract class Vehicle {
abstract start(): void;
drive(): void {
console.log('Driving...');
}
}
In this example, the Vehicle
class is marked as abstract
, which means it cannot be directly instantiated. Derived classes can inherit from it and implement the start
method while having access to the drive
method.
Interfaces
An interface defines a contract that a class must adhere to. It specifies the properties, methods, and events that a class implementing the interface should have.
Consider the following interface definition:
interface Printable {
print(): void;
}
Classes can implement one or multiple interfaces, declaring that they will provide an implementation for the methods defined in those interfaces. For example:
class Document implements Printable {
print(): void {
console.log('Printing document...');
}
}
The Document
class implements the Printable
interface and is required to provide an implementation for the print
method.
Ordinary Classes
Ordinary classes are the most common type of classes. They can be instantiated directly and serve as blueprints for creating objects.
Here’s an example of an ordinary class in TypeScript:
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
sayHello(): void {
console.log(`Hello, my name is ${this.name}`);
}
}
In this example, the Person
class can be instantiated, and objects can be created based on its blueprint. It has a constructor and a method called sayHello
.
Choosing the Right Feature
- Use an abstract class when you want to provide a common base implementation for a group of related classes.
- Use an interface when you want to define a contract that multiple classes should adhere to.
- Use an ordinary class when you want to create objects based on a specific blueprint.
It’s important to understand the distinctions between abstract classes, interfaces, and ordinary classes in TypeScript to make informed design decisions and write clean and modular code.