Skip to main content

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.