Union & Intersection Types
Learn how to combine types with union (|) and intersection (&) operators.
Reading Time
16 min
Lesson
Lesson 11 of 30
Union Types
A union type allows a value to be one of several types, separated by |. The value can be any one of them, but the compiler only lets you use operations valid for every member of the union unless you narrow it first.
A Basic Union
let id: string | number;
id = "abc123"; // OK
id = 42; // OK
id = true; // Error: 'boolean' is not assignable to 'string | number'Narrowing a Union Before Use
To call type-specific methods, you first need to narrow the union to a single type, typically with typeof, instanceof, or a property check.
Narrowing with typeof
function formatId(id: string | number): string {
if (typeof id === "string") {
return id.toUpperCase(); // safe: narrowed to string
}
return id.toFixed(0); // safe: narrowed to number
}Union of Object Types
Unions work with object shapes too, letting a function accept one of several related but distinct structures.
Union of Interfaces
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
side: number;
}
type Shape = Circle | Square;
function area(shape: Shape): number {
if (shape.kind === "circle") {
return Math.PI * shape.radius ** 2;
}
return shape.side ** 2;
}Intersection Types
An intersection type combines multiple types into one, using &. The resulting type has all the members of every combined type — the value must satisfy all of them at once.
A Basic Intersection
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged;
const person: Person = { name: "Alice", age: 30 };Union vs Intersection
| Union (|) | Intersection (&) | |
|---|---|---|
| Meaning | Value is one of the listed types | Value must satisfy all listed types at once |
| Common use | A value with a few valid shapes/forms | Merging multiple smaller shapes into one |
The "kind" Pattern is a Discriminated Union
Giving each member of a union a shared literal property (like kind: "circle") lets TypeScript automatically narrow the type inside conditional checks — this pattern is called a discriminated union.
Best Practice
Use discriminated unions (a shared literal "tag" property) for related-but-different object shapes — it gives you safe, exhaustive narrowing with excellent editor autocomplete.