Implements and Abstract Classes

implements

class X implements I makes the compiler check that the class has everything the interface requires. A class can implement several interfaces.

Example

interface PaymentGateway {
  name: string;
  charge(amountPaise: number): string;
}

class RazorpayGateway implements PaymentGateway {
  name = "Razorpay";
  charge(amountPaise: number): string {
    return `${this.name}: charged Rs. ${amountPaise / 100}`;
  }
}

class StripeGateway implements PaymentGateway {
  name = "Stripe";
  charge(amountPaise: number): string {
    return `${this.name}: charged Rs. ${amountPaise / 100}`;
  }
}

const gateways: PaymentGateway[] = [new RazorpayGateway(), new StripeGateway()];
gateways.forEach((g) => console.log(g.charge(49900)));

Output

Razorpay: charged Rs. 499
Stripe: charged Rs. 499

Abstract Classes

An abstract class cannot be created with new. It can contain real code that subclasses share plus abstract methods that each subclass must implement (the template method pattern).

Example

abstract class Notifier {
  send(to: string, message: string): void {
    const text = this.format(message);
    console.log(`[${this.channel()}] to ${to}: ${text}`);
  }
  protected abstract channel(): string;
  protected abstract format(message: string): string;
}

class SmsNotifier extends Notifier {
  protected channel() { return "SMS"; }
  protected format(m: string) { return m.slice(0, 40); }
}

class EmailNotifier extends Notifier {
  protected channel() { return "EMAIL"; }
  protected format(m: string) { return "Hi,\n" + m; }
}

new SmsNotifier().send("98xxxxxx01", "Your OTP is 482913. Do not share it with anyone.");
new EmailNotifier().send("[email protected]", "Your order has shipped.");

Output

[SMS] to 98xxxxxx01: Your OTP is 482913. Do not share it with
[EMAIL] to [email protected]: Hi,
Your order has shipped.

Forgetting to Implement

Example

A missing interface method (TS2420) and new on an abstract class (TS2511) are both errors.

interface PaymentGateway {
  charge(amountPaise: number): string;
}
class PaypalGateway implements PaymentGateway {}

abstract class Notifier {
  abstract channel(): string;
}
const n = new Notifier();

Compiler output (tsc)

Line 4: error TS2420: Class 'PaypalGateway' incorrectly implements interface 'PaymentGateway'.
  Property 'charge' is missing in type 'PaypalGateway' but required in type 'PaymentGateway'.
Line 9: error TS2511: Cannot create an instance of an abstract class.

Tip: Interface or abstract class? Use an interface for a pure contract. Use an abstract class when subclasses should also share code.