我试图添加一个属性来表达使用typescript从中间件请求对象。但是,我不知道如何向对象添加额外的属性。如果可能的话,我宁愿不用括号。
我正在寻找一个解决方案,允许我写类似的东西(如果可能的话):
app.use((req, res, next) => {
req.property = setProperty();
next();
});
我试图添加一个属性来表达使用typescript从中间件请求对象。但是,我不知道如何向对象添加额外的属性。如果可能的话,我宁愿不用括号。
我正在寻找一个解决方案,允许我写类似的东西(如果可能的话):
app.use((req, res, next) => {
req.property = setProperty();
next();
});
当前回答
公认的答案(和其他答案一样)对我不适用,但是
declare module 'express' {
interface Request {
myProperty: string;
}
}
所做的。希望这能帮助到一些人。
其他回答
为了帮助那些只是在这里寻找其他尝试的人,这是我在2020年5月底试图扩展ExpressJS的Request时所做的工作。我不得不尝试了十几件事,才让这个工作:
在tsconfig的“typeRoots”中翻转每个人推荐的顺序。如果你在tsconfig中有一个rootDir设置,比如"./src",不要忘记删除src路径。例子:
"typeRoots": [
"./node_modules/@types",
"./your-custom-types-dir"
]
自定义扩展('./your-custom-types-dir/express/index.d.ts")的例子。在我的经验中,我不得不使用内联导入和默认导出来使用类作为类型,所以这也显示出来了:
declare global {
namespace Express {
interface Request {
customBasicProperty: string,
customClassProperty: import("../path/to/CustomClass").default;
}
}
}
更新你的nodemon。Json文件,将“——files”命令添加到ts-node,示例:
{
"restartable": "rs",
"ignore": [".git", "node_modules/**/node_modules"],
"verbose": true,
"exec": "ts-node --files",
"watch": ["src/"],
"env": {
"NODE_ENV": "development"
},
"ext": "js,json,ts"
}
在TypeScript中,接口是开放的。这意味着只需重新定义它们,就可以从任何地方向它们添加属性。
考虑到您正在使用这个express.d.ts文件,您应该能够重新定义Request接口以添加额外的字段。
interface Request {
property: string;
}
然后在中间件函数中,req参数也应该具有此属性。您应该能够在不修改代码的情况下使用它。
虽然这是一个非常古老的问题,但我最近偶然发现了这个问题。接受的答案工作得很好,但我需要添加一个自定义接口请求-一个接口,我一直在我的代码中使用,并不能很好地与接受的答案。从逻辑上讲,我尝试了这样做:
import ITenant from "../interfaces/ITenant";
declare namespace Express {
export interface Request {
tenant?: ITenant;
}
}
但这不起作用,因为Typescript处理。d。Ts文件作为全局导入,当它们中有导入时,它们被视为普通模块。这就是为什么上面的代码不能在标准的typescript设置下工作。
这是我最后做的事情
// typings/common.d.ts
declare namespace Express {
export interface Request {
tenant?: import("../interfaces/ITenant").default;
}
}
// interfaces/ITenant.ts
export interface ITenant {
...
}
只需将属性添加到req。params对象。
req.params.foo = "bar"
可选择的解决方案
这实际上并没有直接回答这个问题,但我提供了一个替代方案。我也在与同样的问题作斗争,并尝试了该页面上几乎所有的界面扩展解决方案,但没有一个有效。
这让我停下来思考:“为什么我实际上在修改请求对象?”
使用response.locals
Express开发人员似乎认为用户可能希望添加自己的属性。这就是为什么有一个locals对象。问题是,它不在请求中,而是在响应对象中。
响应。Locals对象可以包含您可能希望拥有的任何自定义属性,这些属性封装在请求-响应周期中,因此不会暴露给来自不同用户的其他请求。
需要存储userId?只需设置response.locals.userId = '123'。没有必要纠结于打字。
它的缺点是,您必须传递响应对象,但很可能您已经这样做了。
https://expressjs.com/en/api.html#res.locals
打字
另一个缺点是缺乏类型安全性。然而,你可以在Response对象上使用泛型类型来定义body和locals对象的结构:
响应< 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
}
);