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.