我正在尝试使用typescript在中间件中添加一个表示请求对象的属性。但是我无法弄清如何向该对象添加额外属性。如果可能,我希望不使用方括号表示。
我正在寻找一种解决方案,使我可以编写类似于以下内容的代码(如果可能):
app.use((req, res, next) => {
req.property = setProperty();
next();
});
我正在尝试使用typescript在中间件中添加一个表示请求对象的属性。但是我无法弄清如何向该对象添加额外属性。如果可能,我希望不使用方括号表示。
我正在寻找一种解决方案,使我可以编写类似于以下内容的代码(如果可能):
app.use((req, res, next) => {
req.property = setProperty();
next();
});
如果您正在寻找与Express4兼容的解决方案,则在这里:
@types/express/index.d.ts: --------必须是/index.d.ts
declare namespace Express { // must be namespace, and not declare module "Express" {
export interface Request {
user: any;
}
}
tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"target": "es2016",
"typeRoots" : [
"@types", // custom merged types must be first in a list
"node_modules/@types",
]
}
}
参考自https://github.com/TypeStrong/ts-node/issues/715#issuecomment-526757308
Cannot find module 'express' or its corresponding type declarations.
- RedGuy11我通过创建一个新类型而不是全局扩展Request类型来解决了这个问题。
import { Request } from 'express'
type CustomRequest = Request & { userId?: string }
你必须使用可选运算符与扩展属性,以避免出现“No overload matches this call”错误。
包版本:
"@types/express": "^4.17.13",
"@types/morgan": "^1.9.3",
"@types/node": "^17.0.29",
"typescript": "^4.6.3",
"express": "^4.18.0",
对于那些依赖npm包ts-node
的人,这个答案将是有益的。
我曾经也遇到过扩展request对象的问题,我查阅了很多stackoverflow上的答案,最终采用了以下策略。
我在以下目录中声明了express的扩展类型:${PROJECT_ROOT}/api/@types/express/index.d.ts
declare namespace Express {
interface Request {
decoded?: any;
}
}
然后将我的tsconfig.json
更新为类似于这样的内容。
{
"compilerOptions": {
"typeRoots": ["api/@types", "node_modules/@types"]
...
}
}
即使按照上述步骤执行后,Visual Studio不再抱怨,但遗憾的是ts-node
编译器仍然会抛出异常。
Property 'decoded' does not exist on type 'Request'.
显然,ts-node
无法定位request对象的扩展类型定义。
最终经过几个小时的研究,我发现 VS Code 没有报错且能够找到类型定义,这意味着 ts-node
编译器出了问题。
在 package.json
中更新启动 script
后问题得以解决。
"start": "ts-node --files api/index.ts",
--files
参数在确定自定义类型定义方面发挥了关键作用。
如需更多信息,请访问:https://github.com/TypeStrong/ts-node#help-my-types-are-missing
--files
标志是 ts-node 中缺失的一部分,这也是为什么我无法让合并的类型对我起作用的原因。 - David Pooley--files
也起作用了。 - undefined以下是我在使用Nestjs和Express时所使用的方法。时间为2020年11月。
创建文件:./@types/express-serve-static-core/index.d.ts
注意:必须要使用以上路径和文件名才能让TypeScript声明合并工作。
import { UserModel } from "../../src/user/user.model";
declare global{
namespace Express {
interface Request {
currentUser: UserModel
}
}
}
将此内容添加到您的tsconfig.json文件中
"typeRoots": [
"@types",
"./node_modules/@types",
]
*.d.ts
文件中导入任何模块时才需要使用 declare global
。 - Kayinterface Request {
property: string;
}
然后在你的中间件函数中,req 参数也应该具有这个属性。你应该能够在不更改代码的情况下使用它。
app.ts
中定义了一个在Request中的属性,如Request.user = {};
,那么userController.ts
该怎么知道它呢? - Nepoxxexpress.Handler
(而不是手动指定 (req: express.Request, res: express.Response, next: express.NextFunction) => any)
),它似乎不引用相同的 Request
,因为它抱怨我的属性不存在。 - Nepoxxdeclare module "express"
,那么我可以让它工作,但如果我使用 declare namespace Express
,就不行了。我更喜欢使用命名空间语法,但它对我来说根本不起作用。 - WillyC为了帮助任何只是想尝试其他方法的人,以下是我在2020年5月底尝试扩展ExpressJS请求时所使用的方法。在成功之前,我试过十几种不同的方法:
"typeRoots": [
"./node_modules/@types",
"./your-custom-types-dir"
]
declare global {
namespace Express {
interface Request {
customBasicProperty: string,
customClassProperty: import("../path/to/CustomClass").default;
}
}
}
{
"restartable": "rs",
"ignore": [".git", "node_modules/**/node_modules"],
"verbose": true,
"exec": "ts-node --files",
"watch": ["src/"],
"env": {
"NODE_ENV": "development"
},
"ext": "js,json,ts"
}
我也遇到同样的问题,解决方法如下:
// /src/types/types.express.d.ts
declare namespace Express {
export interface Request {
user: IUser
}
}
但是需要满足一些条件!
tsconfig.json
文件中"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
},
执行tsc
命令可以构建捆绑包,但是ts-node
无法进行构建。
--files
参数。ts-node --files src/server.ts
"typeRoots": [ "./node_modules/*", "./src/types/*" ]
- TJBlackman一种可能的解决方案是使用“双重转换到任何类型”
1- 使用您的属性定义接口
export interface MyRequest extends http.IncomingMessage {
myProperty: string
}
2- 双重转换
app.use((req: http.IncomingMessage, res: http.ServerResponse, next: (err?: Error) => void) => {
const myReq: MyRequest = req as any as MyRequest
myReq.myProperty = setProperty()
next()
})
-noImplicitany
标志进行很好的编译或者,还有一种快速(未经类型化)的方法:
req['myProperty'] = setProperty()
请不要用自己的属性编辑现有的定义文件,这是不可维护的。如果定义不正确,请打开一个拉取请求。
编辑
参见下面的评论,简单的强制类型转换在这种情况下有效 req as MyRequest
MyRequest
扩展了 http.IncomingMessage
。如果不是这种情况,通过 any
进行双重转换将是唯一的选择。 - Bruno Griederstring
且值类型为any
的键来添加任何其它需要添加的属性。import { Request, Response, NextFunction } from 'express'
interface IRequest extends Request {
[key: string]: any
}
app.use( (req: IRequest, res: Response, next: NextFunction) => {
req.property = setProperty();
next();
});
现在,我们可以向这个对象添加任何其他属性。
app.use((req, res, next) => {
(req as any).property = setProperty();
next();
});
req
对象转换为any
,因此您可以添加任何属性。
请记住,这样做会使得req
对象失去类型安全性。