5 TypeScript Tricks I Use Every Day
From discriminated unions to template literal types — the TypeScript patterns that genuinely changed how I write code.
TypeScript has been around long enough that most developers have moved past the basics. But there's a big gap between "I know how to type a function" and "I actually leverage the type system to catch bugs before runtime." Here are five patterns I reach for constantly.
1. Discriminated Unions Over Optional Fields
The temptation when modeling different states is to make fields optional. Resist it.
With the union, TypeScript narrows automatically inside if (state.status === "success") — no optional chaining needed.
2. satisfies for Type-Checked Literals
Introduced in TypeScript 4.9, satisfies lets you validate a value against a type without widening it.
Without satisfies, you'd need to cast or lose the specific inferred type.
3. Template Literal Types for String APIs
When you're building config objects or event systems, template literal types make invalid strings impossible.
4. infer for Extracting Generic Parts
When you need to pull a type out of another type, infer is your tool.
This is how the built-in utility types like ReturnType, Parameters, and Awaited are implemented.
5. Branded Types to Prevent Mix-ups
TypeScript's structural typing means UserId and ProductId — both string — are interchangeable. Branding prevents that.
You only pay the casting cost once at the boundary (e.g., when reading from a database), and the rest of your codebase stays safe.
These five patterns cover maybe 80% of the "TypeScript-specific" bugs I would have shipped without them. Start with discriminated unions if you pick only one — it's the highest ROI change you can make to an existing codebase.