Union & Intersection Types

A union type says a value can be one of several types — this or that. An intersection type combines several types into one that has everything from all of them — this and that.

Union types

TS union.ts
function formatId(id: number | string): string {
  return `ID-${id}`;
}

console.log(formatId(42));
console.log(formatId("a9x"));
console.log(formatId(true));
tsc output
union.ts:7:20 - error TS2345: Argument of type 'boolean' is
not assignable to parameter of type 'string | number'.

number | string accepts either type, but nothing else — a boolean still isn't allowed, so the third call fails to compile.

Calling a method that isn't on every member

TS narrow-call.ts
function printId(id: number | string) {
  console.log(id.toUpperCase());
}
tsc output
narrow-call.ts:2:15 - error TS2339: Property 'toUpperCase'
does not exist on type 'string | number'.

.toUpperCase() only exists on strings, not numbers — since id could be either, TypeScript refuses to allow the call at all until the code narrows id down to specifically a string first (the Type Narrowing lesson covers exactly how).

Intersection types

TS intersection.ts
interface Named {
  name: string;
}

interface Aged {
  age: number;
}

type Person = Named & Aged;

const p: Person = { name: "Kofi", age: 34 };
console.log(`${p.name} is ${p.age}`);
Output
Kofi is 34

Named & Aged requires both name and age to be present — an intersection adds requirements together, which is the opposite of what a union does.

Note: it's easy to mix up | and & the first time — a union (|) actually ends up being the more restrictive one to work with day-to-day, since you can only safely call something that every member of the union has in common, while an intersection (&) gives you a type with strictly more available properties and methods, not fewer. It helps to read | as "the value could be any one of these" and & as "the value has to satisfy all of these at once."