Unions & Intersections
Union: a value that is one of several types
Section titled “Union: a value that is one of several types”A union A | B describes a value that is either an A or a B. In the sets model it’s the set union — so a union is always wider than its members.
type Id = string | number;
let id: Id = "abc";id = 123; // ✅ both are members of the unionThe catch: while you hold a union, you may only touch the members that all branches share, because the compiler can’t know which one you have yet.
function printId(id: string | number) { id.toUpperCase(); // ❌ toUpperCase does not exist on number. // Only members common to string AND number are available here.}To use type-specific members, you must narrow — the whole next lesson. Until then, a union only exposes the common surface.
Intersection: a value that is all of several types
Section titled “Intersection: a value that is all of several types”An intersection A & B describes a value that is both an A and a B at once. For object types this means “has every property of both” — so an intersection of objects is narrower (more requirements, fewer valid values).
type WithId = { id: string };type WithTimestamps = { createdAt: Date; updatedAt: Date };
type Entity = WithId & WithTimestamps;// must have id AND createdAt AND updatedAt
const e: Entity = { id: "1", createdAt: new Date(), updatedAt: new Date() };This is the idiomatic way to compose object types from small reusable pieces — far more flexible than inheritance because you can mix any combination.
They pull in opposite directions
Section titled “They pull in opposite directions”flowchart TB
subgraph un["A OR B (union)"]
u["more values allowed
fewer members guaranteed"]
end
subgraph inter["A AND B (intersection)"]
i["fewer values allowed
more members guaranteed"]
end Notice the trade in each direction:
- A union allows more values but guarantees fewer members you can safely access (only the common ones).
- An intersection allows fewer values but guarantees more members (all of them).
The edge cases fall out of the sets model
Section titled “The edge cases fall out of the sets model”string & numberisnever— no value is both, so the intersection is the empty set.- A union with
anycollapses toany; a union withneverdrops thenever(T | neveris justT, because adding the empty set changes nothing). - Intersecting object types with a conflicting primitive property can produce
neverfor that property.
type A = { kind: "a"; value: number };type B = { kind: "b"; value: string };type Both = A & B;// kind: "a" & "b" → never; this type is effectively unconstructableThat last one is a hint: when you want “one of these object shapes,” you almost always want a union (A | B) with a shared discriminant field — not an intersection. That’s the discriminated-union pattern in the narrowing lesson.