TypeScript Patterns Every Senior React Developer Should Know
Beyond basic type annotations — advanced TypeScript patterns that prevent entire classes of runtime bugs in large React codebases: discriminated unions, branded types, template literal types, and more.
By POINTNEXIS Team

TypeScript's type system is far more expressive than most teams use in practice. Basic `interface` declarations and `string | null` unions are a starting point — not the destination.
These patterns are drawn from real production codebases where subtle type errors caused bugs that reached users. Each one closes a specific gap that basic typing leaves open.
Discriminated Unions for State Machines
Represent loading states as a discriminated union rather than separate boolean flags. Instead of `isLoading: boolean; data?: User; error?: Error`, use a tagged union: `{ status: 'idle' } | { status: 'loading' } | { status: 'success'; data: User } | { status: 'error'; error: Error }`.
TypeScript narrows the type inside each case branch. You cannot accidentally read `data` in the error case — the compiler prevents it. This eliminates an entire category of `cannot read properties of undefined` runtime errors.
Branded Types for Domain Safety
TypeScript treats `string` aliases as interchangeable. A function expecting a `UserId` accepts any string, allowing you to accidentally pass an `OrderId` in its place. Branded types add a phantom tag that makes them structurally distinct: `type UserId = string & { readonly _brand: 'UserId' }`.
Create constructors that validate and brand at runtime: `function toUserId(raw: string): UserId { if (!isValidUuid(raw)) throw new Error('Invalid UserId'); return raw as UserId; }`. Now the type system enforces domain boundaries across the entire call graph.
Template Literal Types for Typed Strings
Template literal types turn string composition into a type-level operation. Define `type EventName = \`on${Capitalize<string>}\`` to enforce that event handler prop names always start with 'on'. Define API endpoint patterns that TypeScript validates at compile time.
Combine with mapped types to generate typed records from string unions: `type EventHandlers = { [K in EventName]: () => void }` creates a fully-typed event handler object from your event name union.
Satisfies Operator and const Assertions
The `satisfies` operator (TypeScript 4.9+) validates that a value matches a type while preserving its literal type. Use it for configuration objects where you want both type safety and autocompletion of the literal values — without widening to the base type.
POINTNEXIS TypeScript projects use strict mode with `noUncheckedIndexedAccess` enabled. This catches array index access bugs that strict mode alone misses. The initial migration is painful; the long-term maintenance benefit is substantial.