jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Series · 10 parts

Design Patterns in TypeScript

The classic design patterns every senior web engineer should have at hand, explained with runnable TypeScript.

  1. When (and when not) to share a single instance: the Singleton pattern, why ESM modules are already singletons, lazy init, the testability trap, and typed implementations — with exercises.

  2. Centralize object creation: factory functions over `new`, discriminated-union driven factories, the Abstract Factory for families of related objects, and where this beats classes in TypeScript.

  3. Construct complex objects step by step: fluent method chaining, immutable builders, the type-safe staged (phantom-type) builder that makes illegal states unrepresentable, and when an options object is enough.

  4. Swap an algorithm at runtime without touching its caller: the Strategy pattern, why a map of functions is the idiomatic TS form, replacing sprawling if/switch, and injecting behavior for testability.

  5. Decouple "something changed" from "who reacts": the Observer pattern, a fully typed event emitter, the platform EventTarget, Pub/Sub via an event bus, and how signals/reactivity build on the same idea.

  6. Add behavior without touching the original: the Decorator pattern via higher-order functions, wrapping a service to add caching/logging/retry, the middleware chain, and how TS decorators (and the new standard) compare.

  7. Tame third-party and legacy code: the Adapter that makes an incompatible API fit your interface, the Facade that hides a messy subsystem behind one entry point, and the anti-corruption layer that keeps vendor types out of your domain.

  8. Turn actions into data: the Command pattern for dispatch, queues, and undo/redo, the Memento for snapshotting state, and how reducers (Redux-style) are commands in disguise.

  9. Make impossible states impossible: the State pattern, modeling UI/lifecycle with a finite state machine, type-safe transitions via discriminated unions, and why this kills "loading && error" bugs.

  10. Control access and wire your app for testability: the JS Proxy for reactivity/validation/lazy loading, Dependency Injection and Inversion of Control, the composition root, and choosing constructor injection over service-locator.