Problem Statement
Write a typed Express route (Request<Params, ResBody, ReqBody, Query>) and add runtime validation that narrows ReqBody.
Explanation
Type each generic so `req.params`, `req.body`, and `req.query` are fully checked. Then validate the body at runtime with a schema or a custom guard to keep types honest.
Code Solution
SolutionRead Only
import express, { Request, Response } from 'express';
import { z } from 'zod';
const CreateUser = z.object({ name: z.string().min(1), age: z.number().int().positive() });
type Params = { id: string };
type ResBody = { ok: true } | { ok: false; error: string };
type ReqBody = z.infer<typeof CreateUser>;
type Query = { ref?: string };
const app = express();
app.use(express.json());
app.post(
'/users/:id',
(req: Request<Params, ResBody, ReqBody, Query>, res: Response<ResBody>) => {
const parse = CreateUser.safeParse(req.body);
if (!parse.success) return res.status(400).json({ ok: false, error: 'Invalid body' });
// req.body is now ReqBody at compile time; parse.data is validated at runtime
return res.json({ ok: true });
}
);