Unions
What a union is
A union lets a value be one of several types. You build it with the pipe | operator.
let tax: number | string = 10;
tax = "$10"; // Valid: either type is allowed
tax = true; // Error: boolean is not part of the union
Unions are everywhere real data is uncertain — API responses, user input, IDs that might be a number or a string.
You must narrow before using type-specific operations
This is the key rule. On a number | string, you can only do what's valid for both types. To use a method that belongs to just one, you first narrow — prove which type it is:
function format(tax: number | string) {
// tax.toFixed(2) Error: not allowed — string has no toFixed
if (typeof tax === "number") {
return tax.toFixed(2); // Valid: inside here, tax is number
}
return tax.toUpperCase(); // Valid: here tax is string
}
Literal unions — a fixed set of allowed values
Combine unions with literal types to restrict a value to an exact set. Great for status codes, variants, and modes — the compiler suggests the valid options and rejects anything else.
type RequestStatus = "pending" | "success" | "error";
let status: RequestStatus = "pending"; // Valid: status = "done"; // Error: not one of the three
A union widens what a value can be; narrowing recovers what you can do with it. The two always travel together.