node.js 使用 Typescript 扩展 Express Request 对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37377731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:15:10  来源:igfitidea点击:

Extend Express Request object using Typescript

node.jsexpresstypescript

提问by Isak ?gren

I'm trying to add a property to express request object from a middleware using typescript. However I can't figure out how to add extra properties to the object. I'd prefer to not use bracket notation if possible.

我正在尝试添加一个属性来使用打字稿从中间件表达请求对象。但是我不知道如何向对象添加额外的属性。如果可能,我宁愿不使用括号表示法。

I'm looking for a solution that would allow me to write something similar to this (if possible):

我正在寻找一种解决方案,可以让我编写与此类似的内容(如果可能):

app.use((req, res, next) => {
    req.property = setProperty(); 
    next();
});

回答by maximilianvp

You want to create a custom definition, and use a feature in Typescript called Declaration Merging. This is commonly used, e.g. in method-override.

您想要创建自定义定义,并使用 Typescript 中名为Declaration Merging 的功能。这是常用的,例如在method-override.

Create a file custom.d.tsand make sure to include it in your tsconfig.json's files-section if any. The contents can look as follows:

创建一个文件custom.d.ts并确保将其包含在您tsconfig.json的 - 部分(files如果有)中。内容如下:

declare namespace Express {
   export interface Request {
      tenant?: string
   }
}

This will allow you to, at any point in your code, use something like this:

这将允许您在代码中的任何一点使用以下内容:

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)
})

回答by basarat

As suggested by the comments in the index.d.ts, you simply declare to the global Expressnamespace any new members. Example:

正如 中的注释index.d.ts所建议,您只需向全局Express命名空间声明任何新成员。例子:

declare global {
  namespace Express {
    interface Request {
      context: Context
    }
  }
}

Full Example:

完整示例:

import * as express from 'express';

export class Context {
  constructor(public someContextVariable) {
  }

  log(message: string) {
    console.log(this.someContextVariable, { message });
  }
}

declare global {
  namespace Express {
    interface Request {
      context: Context
    }
  }
}

const app = express();

app.use((req, res, next) => {
  req.context = new Context(req.url);
  next();
});

app.use((req, res, next) => {
  req.context.log('about to return')
  res.send('hello world world');
});

app.listen(3000, () => console.log('Example app listening on port 3000!'))

Extending global namespaces is covered more at my GitBook.

在我的 GitBook 中更多地介绍扩展全局命名空间。

回答by JCM

For newer versions of express, you need to augment the express-serve-static-coremodule.

对于较新版本的 express,您需要扩充express-serve-static-core模块。

This is needed because now the Express object comes from there: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8fb0e959c2c7529b5fa4793a44b41b797ae671b9/types/express/index.d.ts#L19

这是必需的,因为现在 Express 对象来自那里:https: //github.com/DefinitelyTyped/DefinitelyTyped/blob/8fb0e959c2c7529b5fa4793a44b41b797ae671b9/types/express/index.d.ts#L19

Basically, use the following:

基本上,使用以下内容:

declare module 'express-serve-static-core' {
  interface Request {
    myField?: string
  }
  interface Response {
    myField?: string
  }
}

回答by max-lt

The accepted answer (as the others) does not works for me but

接受的答案(和其他答案一样)对我不起作用,但

declare module 'express' {
    interface Request {
        myProperty: string;
    }
}

did. Hope that will help someone.

做过。希望这会帮助某人。

回答by Tom Mettam

None of the offered solutions worked for me. I ended up simply extending the Request interface:

提供的解决方案都不适合我。我最终只是简单地扩展了 Request 接口:

import {Request} from 'express';

export interface RequestCustom extends Request
{
    property: string;
}

Then to use it:

然后使用它:

import {NextFunction, Response} from 'express';
import {RequestCustom} from 'RequestCustom';

someMiddleware(req: RequestCustom, res: Response, next: NextFunction): void
{
    req.property = '';
}

Edit: Recent versions of TypeScript complain about this. Instead, I had to do:

编辑:最近版本的 TypeScript 抱怨这个。相反,我必须这样做:

someMiddleware(expressRequest: Request, res: Response, next: NextFunction): void
{
    const req = expressRequest as RequestCustom;
    req.property = '';
}

回答by kaleidawave

After trying 8 or so answers and not having a success. I finally managed to get it working with jd291's comment pointing to 3mards repo.

在尝试了 8 个左右的答案但没有成功之后。我终于设法让它与jd291指向3mards repo的评论一起工作

Create a file in the base called types/express/index.d.ts. And in it write:

在库中创建一个名为types/express/index.d.ts. 并在其中写道:

declare namespace Express {
    interface Request {
        yourProperty: <YourType>;
    }
}

and include it in tsconfig.jsonwith:

并将其包含在tsconfig.json

{
    "compilerOptions": {
        "typeRoots": ["./types"]
    }
}

Then yourPropertyshould be accessible under every request:

然后yourProperty应该可以在每个请求下访问:

import express from 'express';

const app = express();

app.get('*', (req, res) => {
    req.yourProperty = 
});

回答by toskv

In TypeScript, interfaces are open ended. That means you can add properties to them from anywhere just by redefining them.

在 TypeScript 中,接口是开放式的。这意味着您可以通过重新定义它们从任何地方向它们添加属性。

Considering that you are using this express.d.tsfile, you should be able to redefine the Requestinterface to add the extra field.

考虑到您正在使用这个express.d.ts文件,您应该能够重新定义Request接口以添加额外的字段。

interface Request {
  property: string;
}

Then in your middleware function, the reqparameter should have this property as well. You should be able to use it without any changes to your code.

然后在您的中间件函数中,req参数也应该具有此属性。您应该能够在不更改代码的情况下使用它。

回答by 16kb

While this is a very old question, I stumbled upon this problem lately.The accepted answer works okay but I needed to add a custom interface to Request- an interface I had been using in my code and that didn't work so well with the accepted answer. Logically, I tried this:

虽然这是一个非常古老的问题,但我最近偶然发现了这个问题。接受的答案工作正常,但我需要添加一个自定义界面Request- 我在我的代码中使用过的界面,但与接受的界面效果不佳回答。从逻辑上讲,我试过这个:

import ITenant from "../interfaces/ITenant";

declare namespace Express {
    export interface Request {
        tenant?: ITenant;
    }
}

But that didn't work because Typescript treats .d.tsfiles as global imports and when they have imports in them they are treated as normal modules. That is why the code above doesn't work on a standard typescript setting.

但这不起作用,因为 Typescript 将.d.ts文件视为全局导入,并且当它们中有导入时,它们被视为普通模块。这就是为什么上面的代码不适用于标准的打字稿设置。

Here's what I ended up doing

这是我最终做的

// typings/common.d.ts

declare namespace Express {
    export interface Request {
        tenant?: import("../interfaces/ITenant").default;
    }
}
// interfaces/ITenant.ts

export interface ITenant {
    ...
}

回答by Eka putra

Maybe this issue has been answered, but I want to share just a little, now sometimes an interface like other answers can be a little too restrictive, but we can actually maintain the required properties and then add any additional properties to be added by creating a key with a type of stringwith value type of any

也许这个问题已经回答了,但我想分享一点,现在有时像其他答案一样的界面可能有点过于严格,但我们实际上可以维护所需的属性,然后通过创建一个添加任何其他属性键类型为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();
});

So now, we can also add any additional property that we want to this object.

所以现在,我们还可以向这个对象添加我们想要的任何其他属性。

回答by Chandara Chea

If you are looking for solution that works with express4, here it is:

如果您正在寻找适用于 express4 的解决方案,这里是:

@types/express/index.d.ts: --------must be /index.d.ts

@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:

tsconfig.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2016",
    "typeRoots" : [
      "@types", // custom merged types must be first in a list
      "node_modules/@types",
    ]
  }
}

Ref from https://github.com/TypeStrong/ts-node/issues/715#issuecomment-526757308

参考https://github.com/TypeStrong/ts-node/issues/715#issuecomment-526757308