Clean Code with Multiple Classes in TypeScript: Interfaces and Abstract Classes

Introduction

Welcome to the second lesson of the "Clean Code with Multiple Classes" course! In the previous lesson, we explored how to enhance class design and manage code smells effectively. Today, we'll dive into interfaces and abstract classes in TypeScript, which are essential for creating clean, maintainable applications. Leveraging interfaces and abstract classes in TypeScript ensures a clear structure, promoting better organization, scalability, and consistency across your codebase.

Understanding Interfaces

Interfaces in TypeScript define a contract for classes. They specify the methods and properties a class must implement. Unlike traditional class inheritance, interfaces allow the implementation of shared behaviors across unrelated classes, promoting flexibility and reusability.

Here's a simple example:

// Interface defining a contract
interface PaymentProcessor {
    processPayment(amount: number): void;
}

// Class implementing the interface
class CreditCardProcessor implements PaymentProcessor {
    processPayment(amount: number): void {
        console.log(`Processing credit card payment of $${amount}`);
    }
}

In this example, PaymentProcessor is an interface that declares the processPayment method. Any class implementing this interface must provide its implementation of this method. This structure allows different payment processors, such as CreditCardProcessor or PayPalProcessor, to be interchangeable within the codebase.

Using interfaces in TypeScript enhances flexibility and scalability, allowing new payment processors to be added with minimal changes.

Exploring Abstract Classes

Abstract classes in TypeScript work similarly to those in other programming languages. They can't be instantiated directly and can have both abstract and concrete methods. Abstract classes are ideal when you want a common base of functionality for multiple derived classes while still enforcing specific methods.

Consider the following example in TypeScript:

// Abstract class with both abstract and concrete methods
abstract class Animal {
    eat(): void {
        console.log("This animal is eating.");
    }

    abstract makeSound(): void;
}

// Class extending the abstract class
class Dog extends Animal {
    makeSound(): void {
        console.log("Bark!");
    }
}

In this code, Animal is an abstract class that provides a concrete implementation of the eat method while leaving makeSound abstract. The Dog class extends Animal and implements its own version of makeSound. This design pattern allows shared behaviors while requiring derived classes to specify additional functionality.

Abstract classes in TypeScript help reduce code duplication and maintain flexibility by providing shared functionality among related classes.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal