Samuel Fajreldines

I am a specialist in the entire JavaScript and TypeScript ecosystem.

I am expert in AI and in creating AI integrated solutions.

I am expert in DevOps and Serverless Architecture

I am expert in PHP and its frameworks.

+55 (51) 99226-5039 samuelfajreldines@gmail.com

Understanding TypeScript Abstract Classes: A Comprehensive Guide

In modern TypeScript development, abstract classes play a crucial role in designing robust and maintainable applications. They provide a template for other classes to extend, enforcing certain methods to be implemented, and enabling a solid architectural foundation for your codebase.

Understanding Abstract Classes

An abstract class is a special type of class that cannot be instantiated directly. Instead, it serves as a blueprint for other classes to inherit from. Abstract classes can contain implementation details, but they can also have abstract methods that must be implemented by derived classes.

In TypeScript, abstract classes are declared using the abstract keyword. They allow you to define methods and properties that will be shared across subclasses while enforcing certain methods to be implemented by those subclasses.

Abstract Classes in TypeScript

Let's take a look at how abstract classes work in TypeScript. Here's a simple example:

abstract class Animal {
  abstract makeSound(): void; // Abstract method

  move(): void {
    console.log("Moving along!");
  }
}

In this example, Animal is an abstract class. It includes an abstract method makeSound() and a concrete method move(). Any class that extends Animal must provide an implementation for makeSound().

Here's how you might extend the Animal class:

class Dog extends Animal {
  makeSound(): void {
    console.log("Bark!");
  }
}

const myDog = new Dog();
myDog.makeSound(); // Outputs: Bark!
myDog.move(); // Outputs: Moving along!

The Dog class extends Animal and implements the makeSound() method. Now, instances of Dog can use both makeSound() and move() methods.

When to Use Abstract Classes

Abstract classes are particularly useful when you have a group of classes that share a common structure or behavior but also have specific implementations that differ. They allow you to:

  • Enforce a contract: Ensure that all subclasses implement certain methods.
  • Provide shared code: Implement common functionality once in the abstract class.
  • Improve maintainability: Centralize code that is common across multiple classes.

For example, in an application dealing with different types of vehicles, you might have an abstract class Vehicle:

abstract class Vehicle {
  abstract startEngine(): void;

  stopEngine(): void {
    console.log("Engine stopped.");
  }
}

Subclasses like Car and Motorcycle would then implement the startEngine() method according to their specific behavior.

Advantages of Using Abstract Classes

  • Code Reusability: Abstract classes allow you to define common behaviors and reuse code across multiple subclasses.
  • Polymorphism: They enable polymorphic behavior, allowing you to write code that works with abstract classes and any of their subclasses interchangeably.
  • Encapsulation: Abstract classes can encapsulate implementation details that should not be exposed to the outer world.

Abstract Classes vs. Interfaces

While both abstract classes and interfaces are used to define contracts in TypeScript, they serve different purposes.

  • Abstract Classes: Can contain implementation details, including method implementations and properties.
  • Interfaces: Cannot contain implementations. They only declare methods and properties that a class must implement.

Choose abstract classes when you need to share code among several closely related classes and interfaces when you need to enforce a contract on unrelated classes.

Real-World Example: Implementing a Shape Hierarchy

Consider an application that deals with geometric shapes. You can define an abstract class Shape:

abstract class Shape {
  abstract area(): number;

  toString(): string {
    return `Shape with area ${this.area()}`;
  }
}

Subclasses like Circle and Rectangle would implement the area() method:

class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }

  area(): number {
    return Math.PI * this.radius ** 2;
  }
}

class Rectangle extends Shape {
  constructor(private width: number, private height: number) {
    super();
  }

  area(): number {
    return this.width * this.height;
  }
}

const circle = new Circle(5);
console.log(circle.toString()); // Outputs: Shape with area 78.53981633974483

const rectangle = new Rectangle(10, 5);
console.log(rectangle.toString()); // Outputs: Shape with area 50

This approach provides a clean and maintainable structure for your codebase, making it easier to manage complex systems.

Conclusion

Abstract classes in TypeScript are a powerful feature for creating a solid object-oriented architecture. They allow you to enforce specific implementations in derived classes while providing shared functionality. By understanding how to effectively use abstract classes, you can write more maintainable, scalable, and robust TypeScript applications.


Resume

Experience

  • SecurityScoreCard

    Nov. 2023 - Present

    New York, United States

    Senior Software Engineer

    I joined SecurityScorecard, a leading organization with over 400 employees, as a Senior Full Stack Software Engineer. My role spans across developing new systems, maintaining and refactoring legacy solutions, and ensuring they meet the company's high standards of performance, scalability, and reliability.

    I work across the entire stack, contributing to both frontend and backend development while also collaborating directly on infrastructure-related tasks, leveraging cloud computing technologies to optimize and scale our systems. This broad scope of responsibilities allows me to ensure seamless integration between user-facing applications and underlying systems architecture.

    Additionally, I collaborate closely with diverse teams across the organization, aligning technical implementation with strategic business objectives. Through my work, I aim to deliver innovative and robust solutions that enhance SecurityScorecard's offerings and support its mission to provide world-class cybersecurity insights.

    Technologies Used:

    Node.js Terraform React Typescript AWS Playwright and Cypress