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中间件并不矛盾。函数自变量反方差是替换/分型的要求。

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

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

有了这些解决方案,app.get将接受您的自定义中间件,但其自定义的req参数将不会传播到后续的中间件和请求/错误处理程序。也就是说,在其他地方,req.id的类型仍然是undefined,而不是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
}
}
}

最新更新