All posts
TypeScript2026-02-14 ยท 4 min

Types as guardrails, not decoration

A type that mirrors your object shape adds nothing. A type that makes the wrong state unrepresentable pays for itself.


Mirror types do nothing

type Request = { loading: boolean; data?: User; error?: string };

This allows loading: true with both data and error set. The compiler is happy; your UI is not.

Make illegal states unrepresentable

type Request =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: User }
  | { status: 'error'; error: string };

Now the switch statement is exhaustive and the impossible branch never ships.

Small habits that compound

  • Prefer unions over optional flags.
  • Use as const for literal config, then derive types from it.
  • Reserve any for boundaries you immediately validate.