Hint
Union = A OR B (use narrowing to distinguish); intersection = A AND B (merged shape)
Union types (A | B) — a value can be one of several types. You need type narrowing to use type-specific operations.
type StringOrNumber = string | number;
function format(val: StringOrNumber): string {
if (typeof val === 'string') {
return val.toUpperCase(); // narrowed to string
}
return val.toFixed(2); // narrowed to number
}
// Discriminated union — literal type narrows the variant
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number };
function area(s: Shape) {
switch (s.kind) {
case 'circle': return Math.PI * s.radius ** 2;
case 'square': return s.side ** 2;
}
}
Intersection types (A & B) — a value must satisfy ALL types simultaneously. Useful for composing object shapes.
type Serializable = { serialize(): string };
type Loggable = { log(): void };
type SerializableLogger = Serializable & Loggable;
// Must have both serialize() AND log()
// Merging object types
type Admin = User & { adminLevel: number };
// Conflict: if A and B have same property with incompatible types
type Conflict = { id: string } & { id: number };
// id becomes: string & number = never — unusable