TypeScript patterns that catch bugs before runtime
Discriminated unions, exhaustive checks and branded types turn whole classes of runtime errors into compile-time ones.

Types are most valuable when they make an invalid state impossible to write. A few small patterns do most of that work.
Model states as a union
Instead of a bag of booleans, describe each state exactly once. TypeScript then refuses to let you read fields that do not exist in that state.
type RequestState =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string[] }
| { status: "error"; message: string };Ask the compiler for exhaustiveness
A `never` check turns a forgotten branch into a build error rather than a mysterious runtime bug.
function assertNever(value: never): never {
throw new Error(`Unhandled case: ${JSON.stringify(value)}`);
}Prefer one source of truth
- Derive related values instead of storing them twice.
- Keep optional fields truly optional, not empty strings.
- Use narrow types at the boundaries, then trust them inside.
These patterns cost almost nothing at runtime and remove bugs that are otherwise found in production.
- TypeScript
- JavaScript
- Best Practices
