Advanced Type Patterns
Discriminated Unions
A shared literal field lets TypeScript narrow a union to the matching object shape.
discriminated union
A discriminated union uses one field, often named `kind`, to tell each case apart.
Discriminated Unions
discriminated.ts
Replay: real traced execution (multi-file project)
type Circle = {
kind: "circle";
radius: number;
};
type Square = {
kind: "square";
side: number;
};
type Shape = Circle | Square;
function area(shape: Shape): number {
if (shape.kind === "circle") {
return Math.PI * shape.radius * shape.radius;
}
return shape.side * shape.side;
}
const shapeKind: "circle" | "square" = "circle";
const shape: Shape = shapeKind === "circle"
? { kind: "circle", radius: 3 }
: { kind: "square", side: 4 };
const result: number = area(shape);
console.log(`${shape.kind} area=${result.toFixed(2)}`);
type Circle = {
kind: "circle";
radius: number;
};
type Square = {
kind: "square";
side: number;
};
type Shape = Circle | Square;
function area(shape: Shape): number {
if (shape.kind === "circle") {
return Math.PI * shape.radius * shape.radius;
}
return shape.side * shape.side;
}
const shapeKind: "circle" | "square" = "square";
const shape: Shape = shapeKind === "circle"
? { kind: "circle", radius: 3 }
: { kind: "square", side: 4 };
const result: number = area(shape);
console.log(`${shape.kind} area=${result.toFixed(2)}`);
shapeKind ← circle, shape ← [object Object]
17 return shape.side * shape.side;18}1920const shapeKind→ circle: "circle" | "square" = "circle"; //@shapeKind="square"21const shape→ [object Object]: Shape = shapeKind→ circle === "circle"22 ? { kind: "circle", radius: 3 }23 : { kind: "square", side: 4 };24const result: number = area(shape[object Object]);function area(shape: Shape): number
11type Shape = Circle | Square;1213function area(shape[object Object]: Shape): number {14 if (shape.kind === "circle") {if (shape.kind === "circle")
13function area(shape: Shape): number {14 if (shape.kindcircle === "circle") {15 return Math.PI * shape.radius * shape.radius3;16 }result ← 28.274333882308138
22 ? { kind: "circle", radius: 3 }23 : { kind: "square", side: 4 };24const result→ 28.274333882308138: number = area(shape[object Object]);2526console.log(`${shape.kindcircle} area=${result28.274333882308138.toFixed(2)}`);outputcircle area=28.27
shapeKind ← square, shape ← [object Object]
17 return shape.side * shape.side;18}1920const shapeKind→ square: "circle" | "square" = "square";21const shape→ [object Object]: Shape = shapeKind→ square === "circle"22 ? { kind: "circle", radius: 3 }23 : { kind: "square", side: 4 };24const result: number = area(shape[object Object]);function area(shape: Shape): number
11type Shape = Circle | Square;1213function area(shape[object Object]: Shape): number {14 if (shape.kind === "circle") {15 return Math.PI * shape.radius * shape.radius;16 }17 return shape.side * shape.side4;18}result ← 16
22 ? { kind: "circle", radius: 3 }23 : { kind: "square", side: 4 };24const result→ 16: number = area(shape[object Object]);2526console.log(`${shape.kindsquare} area=${result16.toFixed(2)}`);outputsquare area=16.00