Classes & OOP: Building Robust Architectures

Classes & OOP: Building Robust Architectures

TypeScript provides full support for Object-Oriented Programming (OOP). While JavaScript has classes, TypeScript enhances them with type safety, access modifiers, and advanced patterns like abstract classes and interfaces.


1. Class Structure and Properties

A class in TypeScript is a blueprint for creating objects. You must define the types of the class members (properties and methods).

class BankAccount {
    accountNumber: string;
    balance: number;

    constructor(accountNumber: string, initialBalance: number) {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    deposit(amount: number): void {
        this.balance += amount;
    }
}

2. Access Modifiers: Encapsulation

Access modifiers control which parts of your code can see and modify class members.

  • public (Default): Accessible from anywhere.
  • private: Only accessible within the class itself.
  • protected: Accessible within the class and its subclasses (inheritance).
class Employee {
    public name: string;
    private salary: number;
    protected department: string;

    constructor(name: string, salary: number, dept: string) {
        this.name = name;
        this.salary = salary;
        this.department = dept;
    }
}

3. Parameter Properties: The Pro Shortcut

TypeScript provides a shorthand syntax to declare and initialize properties directly in the constructor parameters.

class User {
    // This automatically creates 'public username' and 'private id' properties
    constructor(public username: string, private id: number) {}
}

const user = new User("alice_dev", 101);
console.log(user.username); // OK
// console.log(user.id); // Error: id is private

4. Getters and Setters

You can use get and set to intercept access to a property. This is useful for validation or logging.

class Circle {
    private _radius: number = 0;

    get radius(): number {
        return this._radius;
    }

    set radius(value: number) {
        if (value < 0) throw new Error("Radius cannot be negative");
        this._radius = value;
    }
}

5. Inheritance and Polymorphism

Inheritance allows one class to derive from another. Use the extends keyword.

class Shape {
    constructor(public color: string) {}
    draw() { console.log("Drawing shape..."); }
}

class Square extends Shape {
    constructor(color: string, public size: number) {
        super(color); // Must call the parent constructor
    }

    // Overriding a method
    override draw() {
        console.log(`Drawing a ${this.color} square of size ${this.size}`);
    }
}

6. Abstract Classes

An Abstract Class cannot be instantiated directly. It serves as a base class for other classes. It can contain abstract methods which must be implemented by subclasses.

abstract class Logger {
    abstract log(message: string): void; // No implementation here

    printInfo() {
        console.log("System Logger Initialized");
    }
}

class FileLogger extends Logger {
    log(message: string) {
        // Implementation for writing to a file
    }
}

7. Summary

  • Classes encapsulate data and behavior.
  • Access Modifiers implement the OOP principle of Encapsulation.
  • Inheritance allows for code reuse and logical hierarchies.
  • Abstract Classes define templates for other classes to follow.