首页 > 解决方案 > Express 使用自定义类型的中间件

问题描述

我正在尝试为我的应用程序编写身份验证逻辑。我编写了一个验证令牌的中间件,因此我需要req.id. 我必须编写一个扩展的接口express.Request才能访问id类似的问题)。

import { Request } from "express";

export interface IGetUserAuthInfoRequest extends Request {
    id: number;
}

这就是我在中间件中实现接口以便能够使用该req.id属性的方式。

export const verifyToken = (req: IGetUserAuthInfoRequest, res: Response, next: NextFunction) => {
    req.id = 1; // do something with req.id
    /**
     * some more logic
     **/ 
    next(); 
}

当我尝试调用中间件时,TypeScript 抱怨,我认为这是因为自定义类型。

app.get("/api/try/admin", verifyToken, (req: Request, res: Response) => {
    res.json({message: "try admin"})
});

错误看起来像这样。

Type '(req: IGetUserAuthInfoRequest, res: Response, next: NextFunction) 
=> Response | void' is not assignable to type 
'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | 
RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>'.

我怎样才能正确输入(最好不使用any)?

标签: node.jstypescriptexpress

解决方案


您的自定义中间件与基本 Express 中间件类型(不是其子类型)不兼容。

您的自定义中间件参数比基本中间件的req 参数更专业Request。在类型论语言中,您的自定义中间件在其参数类型中与基本 Express 中间件不逆变。函数参数逆变是替换/子类型化的要求。

对此的一种解决方案是关闭strictFunctionCheckstsconfig.json允许函数参数 bivariance。另一种方法是更改​​自定义请求参数的类型以使其与基本类型兼容:

interface IGetUserAuthInfoRequest extends Request {
  id?: number // making this optional will make your custom middleware type-compatible
}

使用这些变通方法,您的自定义中间件将被 接受app.get,但其自定义req参数不会传播到后续的中间件和请求/错误处理程序。也就是说,req.id仍将是 typeundefined而不是number | undefined在其他地方(它只会在您的自定义中间件中输入)。

我认为正确的解决方案是使用声明合并并将您的自定义Request接口合并到Express命名空间。Express公开了此功能以供自定义中间件使用

declare global {
    namespace Express {
        // These open interfaces may be extended in an application-specific manner via declaration merging.
        // See for example method-override.d.ts (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/method-override/index.d.ts)
        interface Request {}
        interface Response {}
        interface Application {}
    }
}

要合并您的自定义中间件的Request界面:

declare global {
  namespace Express {
    interface Request {
      id?: number
    }
  }
}

推荐阅读