TypeScript Types That Catch Real Bugs
Forget type gymnastics. These five everyday patterns stop the bugs that actually reach production.
1 min read
TypeScript is at its best when it quietly stops a bug before you even run the code. You do not need advanced generics for that. A few simple habits catch most real-world mistakes.
1. Model states, not flags
A request is never loading and failed at the same time, so do not let your types allow it.
type Request =
| { status: 'loading' }
| { status: 'error', message: string }
| { status: 'success', data: User[] }Now every switch on status knows exactly which fields exist.
2. Make impossible values impossible
Use string unions instead of plain strings for anything with a fixed set of options, like sizes, roles or themes.
type Theme = 'light' | 'dark'3. Prefer unknown over any
any switches the type checker off. unknown forces you to check what you received before using it, which is exactly what you want for API responses and user input.
4. Let the compiler check every case
function assertNever(value: never): never {
throw new Error(`Unhandled case: ${value}`)
}Call it in the default branch of a switch, and adding a new case anywhere becomes a compile error until you handle it.
5. Type the edges of your app
Most bugs enter where data crosses a boundary: forms, API calls, local storage. Validate there, give the result a precise type, and the rest of your code can trust it.