Express路由自定义扩展Request类型时出现类型不匹配错误求助
AppRequest Isn't Recognized by Express Router The error you're seeing boils down to TypeScript's function parameter compatibility rules (specifically contravariance) and how Express defines its request handler types. Let’s break this down and fix it step by step:
What’s Going Wrong?
Express’s router.use() expects functions that match the RequestHandler type, which is strictly tied to Express’s native Request, Response, and NextFunction types. Even though your AppRequest extends Request, TypeScript rejects your middleware:
- Express’s
RequestHandleraccepts any baseRequestinstance (including those without yourlogproperty). - Your function only accepts
AppRequest—a more specific type that requireslogto exist. - In TypeScript, function parameters are in a contravariant position: a function expecting a subtype (like
AppRequest) can’t be assigned to a slot that expects a function accepting a supertype (likeRequest). This is because Express might pass a baseRequestto your middleware, which would lack thelogproperty your code relies on.
Solution 1: Custom Handler Type + Type Assertion
First, update your global type definitions to include a custom handler that mirrors Express’s signature but uses your custom types:
// global.d.ts import { Request, Response, NextFunction } from "express"; import { Logger } from "pino"; declare global { interface AppRequest extends Request { log: Logger; } type AppResponse = Response; type AppNextFunction = NextFunction; // Custom handler type matching Express's signature with your types type AppRequestHandler = ( req: AppRequest, res: AppResponse, next: AppNextFunction ) => void | Promise<void>; }
Then, in your router file, use a type assertion to confirm your middleware is safe for Express (just ensure a middleware injecting log runs before this one):
import { Router } from "express"; const router = Router(); const validateSecretMiddleWare: AppRequestHandler = (req, res, next) => { if (process.env.STATS_SECRET !== req.query.secret) { res.sendStatus(404); return; } // Safely use req.log here—you've ensured it exists via a prior middleware req.log.info("Secret validation passed"); next(); }; // Assert your handler matches Express's RequestHandler type router.use(validateSecretMiddleWare as express.RequestHandler); export default router;
Solution 2: Narrow the Request Type Inside the Middleware
If you don’t want to create a custom handler type, you can narrow the req type directly in your middleware using a type assertion:
import { Router, RequestHandler } from "express"; const router = Router(); const validateSecretMiddleWare: RequestHandler = (req, res, next) => { // Narrow req to AppRequest since we know log exists const appReq = req as AppRequest; if (process.env.STATS_SECRET !== appReq.query.secret) { res.sendStatus(404); return; } appReq.log.info("Secret validated"); next(); }; router.use(validateSecretMiddleWare); export default router;
Critical Pre-Requisite
Whichever solution you choose, you must first mount a middleware that injects the log property into the request. This ensures AppRequest is always a valid type for subsequent middleware:
import { RequestHandler } from "express"; import pino from "pino"; export const injectLogger: RequestHandler = (req, res, next) => { // Attach your initialized logger to the request req.log = pino(); next(); }; // Mount this middleware FIRST in your router/app router.use(injectLogger); // Then mount your validation middleware router.use(validateSecretMiddleWare);
内容的提问来源于stack exchange,提问作者Renārs Vilnis

