Challenge 2: Validate a Request Body — Possible Solution ==================================================================== Option A — using zod (the realistic production approach): import { z } from "zod"; const CreateProductSchema = z.object({ name: z.string().min(1), price: z.number().positive(), inStock: z.boolean(), }); // The TypeScript type is DERIVED from the schema — one source of truth. type CreateProductInput = z.infer; function handleCreateProduct(body: unknown): CreateProductInput { // .parse() throws a ZodError if validation fails, otherwise returns a // fully-typed CreateProductInput. return CreateProductSchema.parse(body); } // Usage in an Express-style handler: app.post("/products", (req, res) => { try { const input = handleCreateProduct(req.body); // input.name, input.price, input.inStock are all typed AND validated res.json({ status: "success", data: input }); } catch (err) { res.status(400).json({ status: "error", message: "Invalid product data", code: 400 }); } }); Option B — hand-rolled validator (no dependency, same idea): interface CreateProductInput { name: string; price: number; inStock: boolean; } function isCreateProductInput(value: unknown): value is CreateProductInput { if (typeof value !== "object" || value === null) return false; const v = value as Record; return ( typeof v.name === "string" && v.name.length > 0 && typeof v.price === "number" && v.price > 0 && typeof v.inStock === "boolean" ); } function handleCreateProduct(body: unknown): CreateProductInput { if (!isCreateProductInput(body)) { throw new Error("Invalid product data"); } return body; // narrowed to CreateProductInput by the type guard } WHY THIS WORKS -------------- - In Option A, `z.infer` means the TypeScript type and the runtime check can never drift apart — change the schema, and the type updates automatically on the next compile. - In Option B, the `value is CreateProductInput` type predicate lets `handleCreateProduct` return `body` directly once the guard passes, with TypeScript trusting the narrowed type — the same type-guard mechanism covered in Course 2's Advanced Types chapter. - Either way, an `unknown` request body is never cast with `as` — it's proven to match the shape before being treated as that shape.