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.

Leave a Reply