TypeScript Cheatsheet

Classes

Use this TypeScript reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Class Declaration

class Animal {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  speak(): string {
    return `${this.name} makes a noise.`;
  }
}

const a = new Animal("Dog", 3);
a.speak(); // "Dog makes a noise."

Access Modifiers

class Person {
  public name: string;        // accessible everywhere (default)
  protected age: number;      // accessible in class + subclasses
  private ssn: string;        // accessible only in this class
  readonly id: number;        // can't be changed after construction

  constructor(name: string, age: number, ssn: string, id: number) {
    this.name = name;
    this.age = age;
    this.ssn = ssn;
    this.id = id;
  }
}

// Parameter shorthand (declares AND assigns in one step)
class Point {
  constructor(
    public x: number,
    public y: number,
    private label: string = "point"
  ) {}
}
const p = new Point(1, 2);
p.x; // 1

Private Fields: # vs private

// TypeScript private — compile-time only; accessible via any at runtime
class Safe1 {
  private secret: string = "ts-private";
}

// ECMAScript private field (#) — true runtime privacy
class Safe2 {
  #secret: string = "real-private";

  getSecret() { return this.#secret; }
}

const s = new Safe2();
// s.#secret; // SyntaxError at runtime

Readonly Properties

class Config {
  readonly maxRetries: number;
  readonly name: string;

  constructor(name: string, max: number) {
    this.name = name;
    this.maxRetries = max; // OK in constructor
  }
}

const cfg = new Config("prod", 3);
// cfg.maxRetries = 5; // Error: readonly

Inheritance

class Animal {
  constructor(public name: string) {}
  move(distance = 0) { 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() { console.log("Woof!"); }

  // Override parent method
  move(distance = 5) {
    console.log("Dog is running...");
    super.move(distance); // call parent implementation
  }
}

const d = new Dog("Rex", "Lab");
d.bark();
d.move(10);

Abstract Classes

// Abstract classes can't be instantiated directly
abstract class Shape {
  abstract area(): number;       // must be implemented by subclasses
  abstract perimeter(): number;  // abstract method has no body

  // Concrete method shared by all subclasses
  describe(): string {
    return `Area: ${this.area()}, Perimeter: ${this.perimeter()}`;
  }
}

class Circle extends Shape {
  constructor(public radius: number) { super(); }
  area() { return Math.PI * this.radius ** 2; }
  perimeter() { return 2 * Math.PI * this.radius; }
}

class Rectangle extends Shape {
  constructor(public w: number, public h: number) { super(); }
  area() { return this.w * this.h; }
  perimeter() { return 2 * (this.w + this.h); }
}

// const s = new Shape(); // Error: Cannot instantiate abstract class
const c = new Circle(5);
c.describe();

Implementing Interfaces

interface Serializable {
  serialize(): string;
  deserialize(data: string): this;
}

interface Printable {
  print(): void;
}

// A class can implement multiple interfaces
class Document implements Serializable, Printable {
  constructor(public content: string) {}

  serialize(): string { return JSON.stringify({ content: this.content }); }

  deserialize(data: string): this {
    this.content = JSON.parse(data).content;
    return this;
  }

  print(): void { console.log(this.content); }
}

Static Members

class MathUtils {
  static PI = 3.14159;
  private static instances = 0;

  static circle(r: number): number {
    return MathUtils.PI * r * r;
  }

  static getInstance() {
    return ++MathUtils.instances;
  }
}

MathUtils.PI;          // 3.14159
MathUtils.circle(5);   // 78.53975
MathUtils.getInstance(); // 1

// Static blocks (ES2022 / TS 4.4+)
class Config {
  static readonly DB_URL: string;

  static {
    Config.DB_URL = process.env.DB_URL ?? "localhost";
  }
}

Getters and Setters

class Temperature {
  private _celsius: number;

  constructor(celsius: number) {
    this._celsius = celsius;
  }

  get fahrenheit(): number {
    return this._celsius * 9 / 5 + 32;
  }

  get celsius(): number {
    return this._celsius;
  }

  set celsius(val: number) {
    if (val < -273.15) throw new RangeError("Below absolute zero");
    this._celsius = val;
  }
}

const t = new Temperature(0);
t.celsius;      // 0
t.fahrenheit;   // 32
t.celsius = 100;
t.fahrenheit;   // 212

Generic Classes

class Stack<T> {
  private items: T[] = [];

  push(item: T): void { this.items.push(item); }
  pop(): T | undefined { return this.items.pop(); }
  peek(): T | undefined { return this.items[this.items.length - 1]; }
  get size(): number { return this.items.length; }
  isEmpty(): boolean { return this.items.length === 0; }
}

const numStack = new Stack<number>();
numStack.push(1);
numStack.push(2);
numStack.pop(); // 2

// Constrained generic class
class Repository<T extends { id: number }> {
  private store: Map<number, T> = new Map();

  save(entity: T): void { this.store.set(entity.id, entity); }
  findById(id: number): T | undefined { return this.store.get(id); }
  findAll(): T[] { return [...this.store.values()]; }
}

Class as Type

class Foo {
  x = 0;
  bar() { return "bar"; }
}

// Class name can be used as a type (instance type)
let f: Foo = new Foo();

// typeof ClassName = type of the class constructor
type FooClass = typeof Foo;
const FooCopy: typeof Foo = Foo;

// Extract instance type from class constructor
type FooInstance = InstanceType<typeof Foo>; // same as Foo

// Structural compatibility (TypeScript uses structural typing)
class Bar {
  x = 0;
  bar() { return "bar"; }
}
const b: Foo = new Bar(); // OK — same shape

Mixins Pattern

// Mixin: function that takes a class and returns an extended class
type Constructor<T = {}> = new (...args: any[]) => T;

function Timestamped<Base extends Constructor>(base: Base) {
  return class extends base {
    createdAt = new Date();
  };
}

function Tagged<Base extends Constructor>(base: Base) {
  return class extends base {
    tags: string[] = [];
    addTag(tag: string) { this.tags.push(tag); }
  };
}

class User {
  constructor(public name: string) {}
}

const TimestampedTaggedUser = Tagged(Timestamped(User));
const u = new TimestampedTaggedUser("Alice");
u.createdAt;
u.addTag("admin");
u.name;

override Keyword (TS 4.3+)

class Base {
  greet(): string { return "Hello"; }
  // If a method is removed from Base, overriding it in Derived is an error
}

class Derived extends Base {
  override greet(): string { // 'override' is required with noImplicitOverride: true
    return super.greet() + " World";
  }

  // override nonExistent(): void {} // Error: 'nonExistent' not in Base
}

Class Decorators (Stage 3 / TS 5+)

// Decorator function receives the class
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class BugReport {
  type = "report";
  constructor(public title: string) {}
}

// Decorator factory (takes arguments)
function logged(prefix: string) {
  return function(target: Function) {
    console.log(`${prefix}: ${target.name} defined`);
  };
}

@logged("DEBUG")
class Service {}

Index Signatures in Classes

class StringMap {
  [key: string]: string | (() => string); // index signature

  name: string = "";
  getName(): string { return this.name; }
}

// Dynamic property access
const m = new StringMap();
m["foo"] = "bar";
m.name = "test";

Using Classes as Namespaces

// Inner classes / namespaces
class Outer {
  static Inner = class {
    value = 42;
  };
}
const inner = new Outer.Inner();
inner.value; // 42