12  TypeScript Classes Cheatsheet

12.1 Basic Class Structure

class Person {
  // Properties
  name: string;
  age: number;
  
  // Constructor
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  
  // Method
  greet(): string {
    return `Hello, I'm ${this.name}`;
  }
}

// Usage
const person = new Person("Alice", 30);

12.2 Access Modifiers

class Employee {
  public name: string;        // Accessible everywhere (default)
  private salary: number;      // Only within class
  protected id: number;        // Within class and subclasses
  readonly ssn: string;        // Can't be modified after initialization
  
  constructor(name: string, salary: number, id: number, ssn: string) {
    this.name = name;
    this.salary = salary;
    this.id = id;
    this.ssn = ssn;
  }
}

12.2.1 Shorthand Constructor (TypeScript Feature!)

// Instead of this verbose approach:
class Car {
  make: string;
  model: string;
  year: number;
  
  constructor(make: string, model: string, year: number) {
    this.make = make;
    this.model = model;
    this.year = year;
  }
}

// Use parameter properties (very handy!):
class Car {
  constructor(
    public make: string,
    public model: string,
    private year: number
  ) {}
  // Properties are automatically created and assigned!
}

12.3 Inheritance

class Animal {
  constructor(public name: string) {}
  
  move(distance: number = 0): void {
    console.log(`${this.name} moved ${distance}m`);
  }
}

class Dog extends Animal {
  constructor(name: string, public breed: string) {
    super(name);  // Must call super() before using 'this'
  }
  
  bark(): void {
    console.log("Woof! Woof!");
  }
  
  // Override parent method
  move(distance: number = 5): void {
    console.log("Running...");
    super.move(distance);  // Call parent implementation
  }
}
    Animal
      ↑
   extends
      |
     Dog

12.4 Abstract Classes

abstract class Shape {
  abstract area(): number;  // Must be implemented by subclasses
  abstract perimeter(): number;
  
  // Can have concrete methods
  describe(): string {
    return `Area: ${this.area()}, Perimeter: ${this.perimeter()}`;
  }
}

class Rectangle extends Shape {
  constructor(private width: number, private height: number) {
    super();
  }
  
  area(): number {
    return this.width * this.height;
  }
  
  perimeter(): number {
    return 2 * (this.width + this.height);
  }
}

// const shape = new Shape();  // Error! Can't instantiate abstract class
const rect = new Rectangle(10, 20);  // OK

12.5 Static Members

class MathUtils {
  static PI = 3.14159;
  
  static calculateCircleArea(radius: number): number {
    return MathUtils.PI * radius * radius;
  }
}

// Access without instantiation
console.log(MathUtils.PI);
console.log(MathUtils.calculateCircleArea(5));

12.6 Getters and Setters

class Temperature {
  private _celsius: number = 0;
  
  get celsius(): number {
    return this._celsius;
  }
  
  set celsius(value: number) {
    if (value < -273.15) {
      throw new Error("Temperature below absolute zero!");
    }
    this._celsius = value;
  }
  
  get fahrenheit(): number {
    return (this._celsius * 9/5) + 32;
  }
  
  set fahrenheit(value: number) {
    this.celsius = (value - 32) * 5/9;
  }
}

const temp = new Temperature();
temp.celsius = 25;
console.log(temp.fahrenheit);  // 77

12.7 Implementing Interfaces

interface Flyable {
  fly(): void;
  altitude: number;
}

interface Swimmable {
  swim(): void;
  depth: number;
}

// Class can implement multiple interfaces
class Duck implements Flyable, Swimmable {
  altitude = 0;
  depth = 0;
  
  fly(): void {
    this.altitude = 100;
    console.log("Flying!");
  }
  
  swim(): void {
    this.depth = 2;
    console.log("Swimming!");
  }
}
  Flyable     Swimmable
     ↓            ↓
  implements  implements
     ↓            ↓
     └─── Duck ───┘

12.8 Class as Type

class Point {
  constructor(public x: number, public y: number) {}
}

// Using class as a type
let point: Point;
point = new Point(10, 20);  // OK

// Classes create two things:
// 1. Constructor function
// 2. Type for instances

12.9 Generic Classes

class Box<T> {
  private contents: T;
  
  constructor(value: T) {
    this.contents = value;
  }
  
  getValue(): T {
    return this.contents;
  }
  
  setValue(value: T): void {
    this.contents = value;
  }
}

const numberBox = new Box<number>(42);
const stringBox = new Box<string>("Hello");
const objectBox = new Box<{ name: string }>({ name: "Alice" });

12.10 Method Overloading

class Calculator {
  // Overload signatures
  add(a: number, b: number): number;
  add(a: string, b: string): string;
  
  // Implementation
  add(a: number | string, b: number | string): number | string {
    if (typeof a === 'number' && typeof b === 'number') {
      return a + b;
    }
    return a.toString() + b.toString();
  }
}

12.11 Private Fields (ES2022 Syntax)

class BankAccount {
  #balance: number = 0;  // True private field
  
  deposit(amount: number): void {
    this.#balance += amount;
  }
  
  getBalance(): number {
    return this.#balance;
  }
}

const account = new BankAccount();
// account.#balance;  // Error! Can't access outside class

12.12 Decorators (Experimental)

// Enable in tsconfig.json: "experimentalDecorators": true

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
}

12.13 Quick Comparison with Dart

Feature TypeScript Dart
Constructor shorthand constructor(public name: string) Similar with this.name
Private members private or #field _field convention
Abstract classes abstract class abstract class
Interfaces interface + implements abstract class (no interface keyword)
Static static static
Generics Class<T> Class<T>

12.14 Common Patterns

12.14.1 Singleton Pattern

class Database {
  private static instance: Database;
  
  private constructor() {}  // Private constructor
  
  static getInstance(): Database {
    if (!Database.instance) {
      Database.instance = new Database();
    }
    return Database.instance;
  }
}

12.14.2 Builder Pattern

class UserBuilder {
  private user: Partial<User> = {};
  
  setName(name: string): this {
    this.user.name = name;
    return this;
  }
  
  setAge(age: number): this {
    this.user.age = age;
    return this;
  }
  
  build(): User {
    return this.user as User;
  }
}

// Usage
const user = new UserBuilder()
  .setName("Alice")
  .setAge(30)
  .build();

12.15 Pro Tips

  1. Use readonly for immutable properties - Similar to final in Dart
  2. Parameter properties save boilerplate - Use them in constructors
  3. Prefer interfaces over abstract classes when you only need type structure
  4. Use access modifiers explicitly for clarity (even though public is default)
  5. Consider using # for true private fields if targeting modern JS