Static Members & Parameter Properties

intermediate classes static constructor shortcuts

Two unrelated but very useful class features bundled into one note: static members and parameter properties.

Static members

In simple language, static means “this belongs to the class, not to instances”. Think of it like the only difference is whether we call it on the class itself or on an object made from the class.

class MathHelper {
  static PI = 3.14159;
  static square(n: number) { return n * n; }
}

MathHelper.PI;           // 3.14159
MathHelper.square(4);    // 16

const m = new MathHelper();
m.PI; // Error — PI is on the class, not the instance

Static fields are great for:

  • Constants (HttpStatus.OK = 200).
  • Counters shared across instances.
  • Factory methods (User.fromJSON(...)).
  • Singleton patterns.
class IdGenerator {
  private static counter = 0;
  static next() { return ++IdGenerator.counter; }
}

IdGenerator.next(); // 1
IdGenerator.next(); // 2

Static members can be public, private, protected, and readonly — same modifiers as instance members.

Static blocks

Modern TS supports static initialization blocks for setup that needs more than a single expression.

class Config {
  static envs: string[];
  static {
    Config.envs = process.env.NODE_ENV?.split(",") ?? [];
  }
}

Parameter properties — the constructor shortcut

This one saves SO much boilerplate. Adding an access modifier (or readonly) to a constructor parameter automatically declares AND assigns it as a field.

// the long way
class User {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

// the short way — parameter properties
class User2 {
  constructor(public name: string, public age: number) {}
}

Both produce the exact same class. The second version is way nicer for DTO-style classes.

Any modifier works — public, private, protected, readonly, or combinations:

class Account {
  constructor(
    public readonly id: number,
    private balance: number,
    protected ownerId: number,
  ) {}
}

Mixing parameter properties with regular params

We can mix freely — params with modifiers become fields, params without modifiers stay as plain locals.

class Order {
  constructor(
    public id: number,           // becomes field
    items: string[],             // just a local
  ) {
    console.log(items.length);   // use locally, then it's gone
  }
}

Interview gotchas

  1. Static this: inside a static method, this refers to the CLASS, not an instance. Useful for static factories that need to be inheritable.
class Base {
  static create<T extends typeof Base>(this: T): InstanceType<T> {
    return new this() as InstanceType<T>;
  }
}

class Child extends Base {}
const c = Child.create(); // c: Child
  1. Parameter properties don’t work with destructuringconstructor(public { a, b }: { a: number, b: number }) is not allowed. We have to destructure inside the body.

  2. Static and instance with the same name are allowed — they live in different scopes. Confusing but legal.