Interface & Union Types
Interface & Union Types: A union type is like a restaurant menu line reading 'choose a dessert: baklava OR rice pudding' — only one of those two ever arrives, a third option (say
A union type is like a restaurant menu line reading 'choose a dessert: baklava OR rice pudding' — only one of those two ever arrives, a third option (say, soup) never shows up at the table. So why not just write `any` and say 'the ID can be anything'? Because any removes the waiter's boundary entirely, leaving what comes out of the kitchen completely unpredictable; a union keeps the boundary by saying 'only these two' — Java has no direct equivalent, the closest is faking the same result with generics or method overloads and noticeably more code. The concrete QA payoff: when an API's `id` field sometimes arrives as a number and sometimes as a string, a function typed as `id: number | string` forces you to handle both cases at compile time; a function that assumes a single type silently misbehaves at runtime the moment it meets the other format.
Union type and discriminated union pattern
type Status = "PASS" | "FAIL" | "SKIP" — value can only be one of these three
status: "success" | "error" — this discriminant field tells TypeScript which type it is
if (res.status === 'success') — TypeScript then guarantees res.data exists
Order the steps to handle an API response with discriminated union:
Define union type with 'success' | 'error' discriminant
Branch with if (res.status === "success")
In success branch, safely access res.data
In error branch, display res.message
type ApiResponse = { status: 'success'; data: unknown } | { status: 'error'; message: string } — accessing res.message in the if (res.status === 'success') branch?
Compile error — TypeScript knows message doesn't exist in success branch
Returns undefined — field is absent so undefined
Works — TypeScript makes message optional