Node.js 使用Typescript扩展Express请求对象
我正在尝试添加一个属性,以使用typescript从中间件表达请求对象。但是,我不知道如何向对象添加额外的属性。如果可能的话,我宁愿不使用括号表示法 我正在寻找一个解决方案,允许我写类似的东西(如果可能):Node.js 使用Typescript扩展Express请求对象,node.js,express,typescript,Node.js,Express,Typescript,我正在尝试添加一个属性,以使用typescript从中间件表达请求对象。但是,我不知道如何向对象添加额外的属性。如果可能的话,我宁愿不使用括号表示法 我正在寻找一个解决方案,允许我写类似的东西(如果可能): 一种可能的解决方案是使用“对任何对象进行双重转换” 1-定义与属性的接口 export interface MyRequest extends http.IncomingMessage { myProperty: string } 2-双重铸造 app.use((req: htt
一种可能的解决方案是使用“对任何对象进行双重转换” 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
请参阅下面的注释,在这种情况下,简单的强制转换可以作为MyRequest工作,在TypeScript中,接口是开放式的。这意味着您只需重新定义属性,就可以从任何位置向其添加属性 考虑到您正在使用此文件,您应该能够重新定义请求接口以添加额外字段
接口请求{
属性:字符串;
}
然后在中间件函数中,req参数也应该具有此属性。您应该能够在不更改代码的情况下使用它。您希望创建自定义定义,并使用Typescript中名为的功能。这是常用的,例如在 创建一个文件
custom.d.ts
,并确保将其包含在tsconfig.json
的文件
-部分(如果有)。内容可以如下所示:
declare namespace Express {
export interface Request {
tenant?: string
}
}
这将允许您在代码中的任何时候使用以下内容:
router.use((req, res, next) => {
req.tenant = 'tenant-X'
next()
})
router.get('/whichTenant', (req, res) => {
res.status(200).send('This is your tenant: '+req.tenant)
})
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
}
);
按照的建议,您只需向全局Express
命名空间声明任何新成员。例如:
declare global {
namespace Express {
interface Request {
context: Context
}
}
}
完整示例:
扩展全局名称空间也包括在内。提供的解决方案中没有一个适合我。我最终只是扩展了请求接口:
import {Request} from 'express';
export interface RequestCustom extends Request
{
property: string;
}
然后使用它:
import {NextFunction, Response} from 'express';
import {RequestCustom} from 'RequestCustom';
someMiddleware(req: RequestCustom, res: Response, next: NextFunction): void
{
req.property = '';
}
编辑:根据您的tsconfig,您可能需要改为以下方式:
someMiddleware(expressRequest: Request, res: Response, next: NextFunction): void
{
const req = expressRequest as RequestCustom;
req.property = '';
}
被接受的答案(和其他答案一样)不适合我,但是
declare module 'express' {
interface Request {
myProperty: string;
}
}
是的。希望这会对某人有所帮助。虽然这是一个非常老的问题,但我最近偶然发现了这个问题。接受的答案可以正常工作,但我需要为
请求添加一个自定义接口
——我在代码中使用的一个接口,与接受的答案不太匹配。从逻辑上讲,我试过:
从“./interfaces/ITenant”导入ITenant;
声明命名空间表达式{
导出接口请求{
租户?:ITenant;
}
}
但这不起作用,因为Typescript将.d.ts
文件视为全局导入,当它们包含导入时,它们被视为普通模块。这就是为什么上面的代码不能在标准的排版脚本设置上工作
这就是我最后做的
//打字/common.d.ts
声明命名空间表达式{
导出接口请求{
租户?:导入(“../interfaces/ITenant”)。默认值;
}
}
//接口/ITenant.ts
导出接口ITenant{
...
}
对于较新版本的express,您需要扩展express服务静态核心模块
这是必需的,因为现在Express对象来自于此:
基本上,使用以下方法:
declare module 'express-serve-static-core' {
interface Request {
myField?: string
}
interface Response {
myField?: string
}
}
也许这个问题已经得到了回答,但我想和大家分享一点,
现在,有时候像其他答案一样的界面可能有点过于严格,
但是我们实际上可以维护所需的属性,然后通过创建一个类型为string
且值类型为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();
});
现在,我们还可以向该对象添加任何附加属性。如果您正在寻找可与express4一起使用的解决方案,请参阅:
@类型/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",
]
}
}
在尝试了8个左右的答案但没有成功后,请参考。我终于设法让它工作起来了,他的评论指向了我
在库中创建一个名为types/express/index.d.ts
的文件。在信中写道:
declare namespace Express{
接口请求{
你的财产:;
}
}
并将其包含在tsconfig.json
中,包括:
{
"compilerOptions": {
"typeRoots": ["./types"]
}
}
然后在每个请求下都应该可以访问yourProperty
:
从“express”导入express;
常量app=express();
应用程序获取(“*”,(请求,请求)=>{
req.yourProperty=
});
所有这些回答似乎在某种程度上都是错误的或过时的
这在2020年5月对我起了作用:
在${PROJECT_ROOT}/@types/express/index.d.ts
中:
import * as express from "express"
declare global {
namespace Express {
interface Request {
my_custom_property: TheCustomType
}
}
}
declare module 'express-serve-static-core' {
interface Request {
task?: Task
}
}
在tsconfig.json
中,添加/合并属性,以便:
"typeRoots": [ "@types" ]
干杯。这个答案将对那些依赖npm包ts节点的人有益
我也在为扩展请求对象的问题而挣扎,我在stack overflow中遵循了很多答案,最后遵循了下面提到的策略
我在下面的目录中为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"]
...
}
}
即使完成了上述步骤,VisualStudio也停止了抱怨,但不幸的是,ts节点
编译器仍然使用抛出
Property 'decoded' does not exist on type 'Request'.
显然,ts节点
无法定位请求对象的扩展类型定义
最终在sp之后
Property 'decoded' does not exist on type 'Request'.
"start": "ts-node --files api/index.ts",
import { UserModel } from "../../src/user/user.model";
declare global{
namespace Express {
interface Request {
currentUser: UserModel
}
}
}
"typeRoots": [
"@types",
"./node_modules/@types",
]
import { Request } from "express";
declare global {
namespace Express {
export interface Session {
passport: any;
participantIds: any;
uniqueId: string;
}
export interface Request {
session: Session;
}
}
}
export interface Context {
req: Request;
user?: any;
}```
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
}
);
// ICustomRequset.ts
import { Request } from "express"
export default interface ICustomRequset extends Request {
email?: string;
roles?: Array<string>;
}
// AuthMiddleware.ts
...
export default async function (
req: ICustomRequset,
res: Response,
next: NextFunction
) {
try {
// jwt code
req.email=jwt.email
req.roles=jwt.roles
next()
}catch(err){}
declare module 'express-serve-static-core' {
interface Request {
task?: Task
}
}
{
"compilerOptions": {
"typeRoots": ["./types"]
}
}
app.use((req, res, next) => {
(req as any).property = setProperty();
next();
});
declare namespace e {
export interface Request extends express.Request {
user:IUserReference,
[name:string]:any;
}
export interface Response extends express.Response {
[name:string]:any;
}
}
export type AsyncRequestHandler = (req:e.Request, res:e.Response, logger?:Logger) => Promise<any>|Promise<void>|void;
export type AsyncHandlerWrapper = (req:e.Request, res:e.Response) => Promise<void>;
app.post('some/api/route', asyncHandlers(async (req, res) => {
return await serviceObject.someMethod(req.user, {
param1: req.body.param1,
paramN: req.body.paramN,
///....
});
}));