JSTAcademy
0 XP
Dashboard
Crash Courses
Union, Literal & Discriminated Union Types
11 min
Masters+175 XP
Crash Courses · Masters

Union, Literal & Discriminated Union Types

Model real-world states precisely with union types, literal types, and discriminated unions.
11 min read+175 XP on completionCert: TypeScript Crash Course
Tap any word in the text below to start reading from there.

Union, Literal & Discriminated Union Types

TypeScript's most powerful feature for modeling real-world states precisely.

Union Types

type StringOrNumber = string | number

function formatId(id: StringOrNumber): string {
  if (typeof id === 'string') {
    return id.toUpperCase()  // id is string here
  }
  return id.toString()       // id is number here
}

Literal Types

type Level = 'Basic' | 'Masters' | 'PhD' | 'Next-Gen AI'
type Status = 'pending' | 'active' | 'cancelled' | 'completed'

const courseLevel: Level = 'Masters'
// const bad: Level = 'Beginner'  // Error — not in union

function setStatus(id: string, status: Status): void { }
setStatus('user_1', 'active')    // OK
// setStatus('user_1', 'removed') // Error

Discriminated Union State Machine Pattern

type LoadingState =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: User[] }
  | { status: 'error'; message: string }

function renderState(state: LoadingState) {
  switch (state.status) {
    case 'idle':    return <div>Ready</div>
    case 'loading': return <Spinner />
    case 'success': return <UserList users={state.data} />   // state.data typed
    case 'error':   return <Error msg={state.message} />     // state.message typed
  }
}

The discriminant (status) tells TypeScript which variant you are handling additional properties are typed correctly.

Exhaustive Checks with never

function assertNever(x: never): never {
  throw new Error('Unexpected value: ' + x)
}

function handleStatus(status: Status): string {
  switch (status) {
    case 'pending':   return 'Waiting'
    case 'active':    return 'Running'
    case 'cancelled': return 'Stopped'
    case 'completed': return 'Done'
    default:          return assertNever(status)
  }
}
// Add a new Status variant → TypeScript errors at assertNever
0%