5) Typescript Union Types
Union Types
A Union Type allows a variable to hold multiple possible types. A union type is created using the|(pipe) symbol between the types.type Status = "loading" | "success" | "error"; // OR let value: string | number;This means
valuecan be either astringor anumber.
i) Union Types with Propstype ButtonProps = { label: string; variant: "primary" | "secondary"; }; function Button({ label, variant }: ButtonProps) { return ( <button className={variant}> {label} </button> ); }<Button label="Save" variant="primary" /> // If someone writes <Button label="Save" variant="danger" /> // TypeScript throws an error because "danger" is not allowed.ii) Union Types with State
const [status, setStatus] = useState< "idle" | "loading" | "success" | "error" >("idle");Narrowing
TypeScript cannot automatically know which type is currently being used inside a union. Narrowing helps TypeScript determine the exact type.
i) Example Without Narrowingfunction print(value: string | number) { console.log(value.length); } // Property 'length' does not exist on type 'number' // Because number doesn't have .length.ii) Narrowing Using typeof
function print(value: string | number) { if (typeof value === "string") { console.log(value.length); } else { console.log(value.toFixed(2)); } }Now TypeScript understands:
inside if → value is string
inside else → value is number
iii) Narrowing in Reacttype Props = { data: string | string[]; }; function Display({ data }: Props) { return ( <div> {typeof data === "string" ? data : data.join(", ")} </div> ); }Type Guards
A Type Guard is logic that checks a type during runtime and helps TypeScript narrow the type.
i) typeof -typeof value === "string"
ii) instanceof -value instanceof Date
iii) in operator -"name" in obj
iv) Custom type guard -isUser(value)
In Operatortype Admin = { role: string; }; type User = { email: string; }; function printPerson(person: Admin | User) { if ("role" in person) { console.log(person.role); } else { console.log(person.email); } }Custom Type Guard
function isString(value: unknown): value is string { return typeof value === "string"; } function print(value: unknown) { if (isString(value)) { console.log(value.toUpperCase()); } }Unknown Type
unknownis a safer version ofany// with any let value: any = "Hello"; value.toUpperCase(); // allowed // No type safety.// with unknown let value: unknown = "Hello"; value.toUpperCase(); // Errorunknown vs any
i) unknown - Type-safe
any - No type checking
ii) unknown - Safer
any - Dangerous
iii) unknown - Requires narrowing
any - Allows everythingasync function fetchData(): Promise<unknown> { const response = await fetch("/api/users"); return response.json(); }never Type
never means: This value should never happen.
Used for: impossible states, exhaustive checks, functions that never return.
React Exampletype State = { count: number; }; type Action = | { type: "increment" } | { type: "decrement" }; function reducer( state: State, action: Action ): State { switch (action.type) { case "increment": return { count: state.count + 1 }; case "decrement": return { count: state.count - 1 }; default: const exhaustive: never = action; return state; } }Concepts
i) Union Types - Allow multiple types
ii) Narrowing - Reduce union into specific type
iii) Type Guards - Runtime checks for narrowing
iv) unknown - Safer alternative to any
v) never - Impossible values/exhaustive checks