Abstract Classes in Typescript

Abstract Classes in Typescript

In Typescript, the classes can inherit from another class to share methods and properties between classes. Also, Typescript support abstract class. Let me show you why and when to use it.

For example, we have a base class Subscription and create the new subclass FrenchSubscription with his sign method implementation.

class Subscription {
    url: string = "";
    constructor(public name: string) {
        this.name = name;
    }
    sign(): string {
        return "Signup!!";
    }
}

class FrenchSubscription extends  Subscription {
    url: string = "http://www.typescript.fr";
    sign(): string {
        return `Bonjour ${this.name} please go to ${this.url}`;
    }
}

We create a new SubscriptionManager class to process a list of subscriptions and use the sign method to show a message.

The subscription manager will support future subscription's child classes, like EnglishSubscription class.

The SubscriptionManager has a process method to iterate over every subscription and call the sign method to show the message.

class SubscriptionManager {
    static subscriptions: Array<Subscription> = [];
    static process() {
        this.subscriptions.forEach((p) => {
            let message =  p.sign();
            console.log(message)
        })
    }
}

The SubscriptionManager is ready to works, then add a Subscription instance to subscriptions and process it.

let france = new FrenchSubscription('Paris');
SubscriptionManager.subscriptions.push(france);

SubscriptionManager.process();
[nodemon] starting `node Student.js`
Bonjour Paris please go to http://www.typescript.fr.

Nodemon runs the app, and perfect!! Everything works! Go to live because my code works but has some weaknesses.

A new developer comes to the company and needs to create a new English class, which will inherit from the Subscription base class. He creates EnglishSubscription and the sign method because everything looks fine IDE, and the compiler won't complain about it. Commit his changes.

class EnglishSubscription extends Subscription {
    url: string = "http://www.typescript.us";
    sign() {
        return false;
    }
}

The service starts to use the EnglishSubscription class, and it is a Subscription object that will contain the sign method.

let france = new FrenchSubscription('Paris');
let ny = new EnglishSubscription('New York');

SubscriptionManager.subscriptions.push(france);
SubscriptionManager.subscriptions.push(ny)

SubscriptionManager.process();

CRASH!! The result is not as we expect!!!

Bonjour Paris please go to http://www.typescript.fr
false

We had a bug and error, the method exists but doesn't fit with the initial contract and the developer doesn't know how what is the contract with the SubscriptionManager.

Sometimes we need to be sure the developer fits with the goal of the base class and be sure every child class based on it implements all members with field, methods, and signature.

Then, it is time to use the abstract class, using the abstract keyword before the method and class name them our normal class becomes to be an abstract class and every child class must implement the method with the expected signature.

Tip: The abstract methods don’t have an implementation.

abstract class Subscription {
    url: string = "";
    constructor(public name: string) {
        this.name = name;
    }
    abstract sign(): string { }
}

The child classes from Subscription must implement the sign method with the signature, if not the IDE and compiler will raise an error.

 Property 'sign' in type 'EnglishSubscription' is not assignable to the exact property in base type 'Subscription'. 
  Type '() => boolean' is not assignable to type '() => string'.     Type 'boolean' is not assignable to type 'string'.

Using abstract, the developers understand what the goal of the base class Subscription is, and his methods also, we are sure for each child class implements the methods for the proposal with an expected result but different behavior, and our code is safe and flexible.

Hopefully, that will give you a bit of help with abstract classes in Typescript. If you enjoyed this post, share it.

Photo by Karsten Winegeart on Unsplash