TypeScript Advanced Types: satisfies, Narrowing, and Branded Types

Move beyond basic interfaces with TypeScript satisfies operator, discriminated unions, template literal types, and branded types for safer domain modeling in large codebases.

TypeScript Advanced Types: satisfies, Narrowing, and Branded Types

When Interfaces Are Not Enough

TypeScript's structural typing is powerful but can erode precision: widening literals, losing autocomplete on const objects, and allowing invalid states that compile silently. Modern TypeScript (4.9+) adds tools that preserve developer ergonomics while tightening correctness.

The satisfies Operator

satisfies validates that an expression matches a type without widening it to that type. You keep literal inference and still catch missing or extra keys.

type Route = Record<string, { path: string; method: 'GET' | 'POST' }>;

const routes = {
  home: { path: '/', method: 'GET' },
  login: { path: '/login', method: 'POST' },
} satisfies Route;

// routes.home.method is 'GET' | 'POST', not string
// Typo in key or method is caught at compile time

Discriminated Unions for State Machines

Model UI and API states with a shared discriminant field (kind, status, type). Control flow narrowing eliminates impossible branches without runtime checks scattered everywhere.

type AsyncState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error };

function render<T>(state: AsyncState<T>) {
  switch (state.status) {
    case 'success': return state.data; // narrowed
    case 'error': return state.error.message;
    default: return null;
  }
}

Branded Types for Domain Safety

Prevent mixing primitive IDs at compile time by branding strings:

type UserId = string & { readonly brand: unique symbol };
type OrderId = string & { readonly brand: unique symbol };

function getUser(id: UserId) { /* ... */ }
// getUser(orderId) // compile error

Template Literal Types

Generate CSS property unions, event names, or API route strings from const tuples. Pair with as const for design-system tokens and typed environment variable maps.

Advanced TypeScript is not academic. It reduces production bugs, improves IDE navigation, and documents domain rules in code. Invest in types at boundaries: API payloads, config objects, and shared state shapes.

Explore Topics

#TypeScript#satisfies#Type Narrowing#Discriminated Unions#Branded Types#Static Typing#JavaScript