You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express路由自定义扩展Request类型时出现类型不匹配错误求助

Why Your Custom 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 RequestHandler accepts any base Request instance (including those without your log property).
  • Your function only accepts AppRequest—a more specific type that requires log to 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 (like Request). This is because Express might pass a base Request to your middleware, which would lack the log property 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:54:46