CodePark/ questions / Value objects, equality & invariants
START PRACTICINGPRACTICE
Backend question · Object-oriented programming › Value objects, equality & invariants

How do you make a class instance immutable in TypeScript? Compare readonly, Readonly<T>, Object.freeze and returning new instances.

Immutable means the object can't change after it is created. Each tool covers a different part:

  • readonly fields stop reassignment at compile time only. They are shallow: a readonly items: string[] can still be pushed to. They disappear in the JavaScript output.
  • Readonly<T> makes every top-level property of a type readonly. It is also compile-time only and shallow. Use readonly string[] or ReadonlyArray for arrays.
  • Object.freeze(this) blocks changes at runtime. In strict mode a write throws a TypeError. It is shallow too, so freeze nested objects yourself. It also stops subclasses from adding fields after super().
  • Operations return new instances: money.add(other) returns a new Money. It never changes this.

A good recipe for a value object:

  • readonly fields with primitive or readonly types
  • a constructor or static factory that validates
  • methods that return new instances
  • Object.freeze if JavaScript code or untyped input could change it

Why bother? An immutable object can be shared between requests and cached safely. No caller can change it under another caller.

  • readonly and Readonly<T> are compile-time checks only.
  • All of these tools are shallow, so nested arrays and objects need their own protection.
  • Object.freeze blocks changes at runtime and throws in strict mode.
  • Value object methods should return new instances instead of changing this.
  • Immutable objects are safe to share and cache.