替代解决方案
这实际上并没有直接回答这个问题,但我提供了一个替代方案。我一直在为同样的问题苦苦挣扎,并尝试了此页面上的几乎所有接口扩展解决方案,但都没有奏效。
这让我停下来思考:“我为什么要修改请求对象?”。
使用response.locals
Express 开发人员似乎认为用户可能想要添加自己的属性。这就是为什么有一个locals 对象。问题是,它不在 request 中,而是在 response 对象中。
response.locals 对象可以包含您可能想要的任何自定义属性,封装在请求-响应周期中,因此不会暴露给来自不同用户的其他请求。
需要存储用户 ID?只需设置response.locals.userId = '123'。无需为打字而苦恼。
它的缺点是您必须传递响应对象,但很可能您已经在这样做了。
https://expressjs.com/en/api.html#res.locals
打字
另一个缺点是缺乏类型安全性。但是,您可以使用 Response 对象上的泛型类型来定义 body 和 locals 对象的结构:
Response<MyResponseBody, MyResponseLocals>
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts#L127
注意事项
您不能真正保证 userId 属性确实存在。您可能需要在访问它之前进行检查,尤其是在对象的情况下。
使用上面的例子添加一个 userId,我们可以有这样的东西:
interface MyResponseLocals {
userId: string;
}
const userMiddleware = (
request: Request,
response: Response<MyResponseBody, MyResponseLocals>,
next: NextFunction
) => {
const userId: string = getUserId(request.cookies.myAuthTokenCookie);
// Will nag if you try to assign something else than a string here
response.locals.userId = userId;
next();
};
router.get(
'/path/to/somewhere',
userMiddleware,
(request: Request, response: Response<MyResponseBody, MyResponseLocals>) => {
// userId will have string type instead of any
const { userId } = response.locals;
// You might want to check that it's actually there
if (!userId) {
throw Error('No userId!');
}
// Do more stuff
}
);