Lab 07: Runtime Validation Advanced
Step 1: Environment Setup
docker run -it --rm node:20-alpine sh
npm install -g typescript ts-node
mkdir lab07 && cd lab07
npm init -y
npm install zod
echo '{"compilerOptions":{"module":"commonjs","target":"es2020","strict":true,"esModuleInterop":true}}' > tsconfig.jsonStep 2: Discriminated Unions
// shapes.ts
import { z } from 'zod';
// z.discriminatedUnion is faster than z.union — checks the discriminator key first
const ShapeSchema = z.discriminatedUnion('kind', [
z.object({
kind: z.literal('circle'),
radius: z.number().positive(),
}),
z.object({
kind: z.literal('rectangle'),
width: z.number().positive(),
height: z.number().positive(),
}),
z.object({
kind: z.literal('triangle'),
base: z.number().positive(),
height: z.number().positive(),
}),
]);
type Shape = z.infer<typeof ShapeSchema>;
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'rectangle':
return shape.width * shape.height;
case 'triangle':
return 0.5 * shape.base * shape.height;
}
}
const shapes = [
{ kind: 'circle', radius: 5 },
{ kind: 'rectangle', width: 4, height: 6 },
{ kind: 'triangle', base: 3, height: 8 },
];
shapes.forEach(raw => {
const shape = ShapeSchema.parse(raw);
console.log(`${shape.kind}: area = ${area(shape).toFixed(2)}`);
});Step 3: Lazy Recursive Schemas
Step 4: Transform and Preprocess
Step 5: Branded Types for Nominal Typing
Step 6: ZodError Formatting
Step 7: Complex Schema Composition
Step 8: Capstone — API Validation Middleware
Summary
Feature
API
Use Case
Last updated
