TypeScript
Practical TypeScript: Patterns I Use Every Day
May 5, 2026
After years of TypeScript I have settled on a handful of patterns that show up in nearly every project.
**Discriminated unions over boolean flags**
Instead of `{ loading: boolean, error: boolean, data: T | null }`, use `{ status: 'idle' | 'loading' | 'error' | 'success', data?: T, error?: Error }`. The compiler enforces valid combinations.
**const assertions for config objects**
`as const` narrows string arrays to their literal types, making them safe to use as union members without a separate type declaration.
**Type predicates for runtime narrowing**
A function typed `(x: unknown): x is Post` lets you validate API responses and get full type safety downstream with no casting.
**Mapped types for form state**
`type FormErrors<T> = Partial<Record<keyof T, string>>` generates an error map type from any data type automatically.
**Satisfies operator for config validation**
`config satisfies Config` checks the shape without widening the type — you keep the literal types while still getting validation.
None of these are exotic. They are the patterns that make code easier to maintain six months later.