node.js - 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
)?
解决方案
您的自定义中间件与基本 Express 中间件类型(不是其子类型)不兼容。
您的自定义中间件参数比基本中间件的req
参数更专业Request
。在类型论语言中,您的自定义中间件在其参数类型中与基本 Express 中间件不逆变。函数参数逆变是替换/子类型化的要求。
对此的一种解决方案是关闭strictFunctionChecks
以tsconfig.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
}
}
}
推荐阅读
- postgresql - 如何通过 exec odoo11 容器运行 odoo 11
- python - 如果另一个失败,pytest 可以运行测试吗?
- tensorflow - 多输入深度学习中的平均层
- r - R:cat() 一致地打印出 unicode 到控制台,但不打印到文件
- java - 在 NetBeans Maven 项目中设置链接源属性
- html - 在下一次加载 .html 时使用 app.js 加载从 html 表单保存的变量
- node.js - Sequelizejs从关系表中获取字段到关联belongsToMany
- ruby-on-rails - 如何更新项目中的 Rails 版本?Bundler 找不到 gem “activemodel” 的兼容版本
- c# - 如何将注册中设置的值显示到 seevalue() 函数中?范围
- javascript - 如何通过状态向单选按钮添加标签