Unlocking the Power of Abstract Classes in TypeScript
Setting Up a Scratchpad Project
To explore the world of abstract classes, let’s create a Node.js project and install TypeScript as a dependency. This will give us a package.json
file and a tsconfig.json
file to configure our TypeScript setup.
{
"compilerOptions": {
"target": "es6"
}
}
We’ll update the tsconfig.json
file to target a newer version of JavaScript that supports classes. Finally, we’ll create an index.ts
file to write our code and add a script to compile our TypeScript to JavaScript and run it with Node.
node index.js
Creating an Abstract Class
Now, let’s define an abstract class called ViewModel
with a constructor that takes an id
parameter. This ensures that every subclass of ViewModel
will have an id
value.
abstract class ViewModel {
protected id: number;
constructor(id: number) {
this.id = id;
}
}
The Rules of Abstract Classes
When working with abstract classes, there are two essential rules to keep in mind:
- Subclasses can either omit a constructor, allowing the base class constructor to become the default.
- Implement their own constructor that invokes the base class constructor with the correct arguments.
Putting the Abstract Class to the Test
Let’s see what happens when we try to instantiate our abstract class directly.
// Error: Cannot create an instance of an abstract class.
const viewModel = new ViewModel(1);
As expected, we’ll get a compilation error. However, the transpiled JavaScript code will still be valid, even if the source code isn’t.
Subclassing without a New Constructor
Next, let’s create a subclass of ViewModel
without implementing a new constructor.
class UserViewModel extends ViewModel {
// No constructor needed
}
The TypeScript compiler will ensure that we pass the required id
parameter to the base class constructor.
const userViewModel = new UserViewModel(1);
Subclassing with a New Constructor
Now, let’s create a subclass with a new constructor that takes two parameters.
class AdminViewModel extends ViewModel {
private adminRole: string;
constructor(id: number, adminRole: string) {
super(id);
this.adminRole = adminRole;
}
}
We’ll need to invoke the base class constructor with the correct arguments using the super
keyword.
const adminViewModel = new AdminViewModel(1, 'admin');
The Importance of Abstract Classes
In conclusion, TypeScript’s abstract classes provide a powerful way to enforce structure and consistency in our code. By following the rules of abstract classes, we can ensure that our subclasses are correctly implemented and maintainable.