Unions of literals replace magic strings and model the 'one of these' choices that appear in every domain.
A union type A | B means a value can be either. string | number accepts both; User | null is how you model "maybe there's a user".
A literal type is a single exact value used as a type: "left", 42, true. On their own they're odd, but unions of literals are one of TypeScript's best features:
type Align = "left" | "center" | "right";
function align(text: string, how: Align) { ... }
align("hi", "centre"); // error: not assignable to AlignYou get autocompletion for the allowed values and a compile error for typos, at zero runtime cost — the values stay ordinary strings. The same works for numbers (type Dice = 1 | 2 | 3 | 4 | 5 | 6) and boolean is literally true | false.
What can you do with a union value? Only the operations valid for every member. With id: string | number you can call id.toString() (both have it) but not id.toUpperCase(). To use member-specific operations you narrow the union first, typically with a check like typeof id === "string" — that's the next lesson.
The type keyword creates an alias — a name for any type expression, including unions, which interfaces can't express.
Remember literal widening: let how = "left" is a string, so passing it where Align is expected fails. Either annotate (let how: Align = "left") or use const.
Unions also apply to arrays: (string | number)[] is an array whose elements can each be either, while string[] | number[] is either an all-string or an all-number array.
Example
type Align = "left" | "center" | "right";
type Id = string | number;
function pad(text: string, width: number, how: Align = "left"): string {
if (how === "left") return text.padEnd(width);
if (how === "right") return text.padStart(width);
const space = width - text.length;
return " ".repeat(Math.floor(space / 2)) + text + " ".repeat(Math.ceil(space / 2));
}
function describe(id: Id): string {
return `#${id.toString()}`; // OK: both members have toString
}
console.log(`[${pad("hi", 6, "center")}]`, describe(7), describe("x7"));
let choice = "right"; // string, not "right"
// @ts-expect-error -- Argument of type 'string' is not assignable to 'Align'
pad("hi", 6, choice);
const fixed = "right"; // "right"
pad("hi", 6, fixed);Remember
A | B= a value of either type- Unions of string literals replace magic strings with zero runtime cost
- On a union you can only use what every member supports — narrow first
Watch out for
- Losing a literal type through
letand then failing to pass it to a function expecting the union.