Explain union (|) and intersection (&) types.
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
A union accepts a value of any listed type — 'this OR that'. An intersection combines multiple types into one — 'all of these at once'. Unions model alternatives; intersections compose capabilities.
Detailed explanation
Unions express finite alternatives: type Result = Ok | Err, string | number parameters, literal unions for statuses. To *use* a union safely you narrow it (typeof, in, discriminant checks) until TypeScript knows which member you hold. Literal subsets are assignable upward (a 'pending' literal fits into Status) but not downward. Intersections merge requirements: type Admin = User & { permissions: Permission[] } needs every member's properties satisfied. They're how mixins and capability composition work, and they power utility patterns like Pick combined with generics. A subtle consequence: overlapping unions intersect to their shared members, and incompatible property types inside an intersection collapse to never — which is why A & B sometimes yields unusable objects if members conflict. Discriminated unions (shared literal tag field + narrowing) remain the single most valuable pattern here.
Example
type Id = string | number;
function find(id: Id) {
if (typeof id === 'string') return db.bySlug(id); // narrowed
return db.byId(id);
}
type Serializable = { toJSON(): string };
type Named = { name: string };
type Entity = Named & Serializable; // must have bothInterview tip
Use plain English — OR vs AND — then jump straight to discriminated unions as the practical payoff; it's where this question is really heading.
Common mistakes
- Forgetting unions require narrowing before property access.
- Expecting & to create a union-like choice instead of a merged requirement.