Extend Express Request с помощью Typescript
Я пытаюсь добавить свойство для выражения объекта запроса из промежуточного программного обеспечения с помощью typescript. Однако я не могу понять, как добавить дополнительные объекты к объекту. Идентификатор предпочитает, если возможно, использовать нотацию с кронштейном.
Im ищет решение, которое позволило бы мне написать что-то похожее на это (если возможно):
app.use((req, res, next) => {
req.property = setProperty();
next();
});
Ответы
Ответ 1
Вы хотите создать собственное определение и использовать в Typescript функцию под названием Объявление слияние. Это обычно используется, например, в method-override
.
Создайте файл custom.d.ts
и убедитесь, чтобы включить его в ваших tsconfig.json
files
, если какой - либо -section. Содержание может выглядеть следующим образом:
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)
})
Ответ 2
Как следует из комментариев в index.d.ts
, вы просто объявляете глобальному пространству имен Express
новых членов. Пример:
declare global {
namespace Express {
interface Request {
context: Context
}
}
}
Полный пример:
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!'))
Расширение глобальных пространств имен рассмотрено в моей GitBook.
Ответ 3
Принятый ответ (как и другие) не работает для меня, но
declare module 'express' {
interface Request {
myProperty: string;
}
}
сделал. Надеюсь, что это поможет кому-то.
Ответ 4
Для более новых версий Express вам необходимо дополнить модуль express-serve-static-core
.
Это необходимо, потому что теперь объект Express приходит оттуда: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8fb0e959c2c7529b5fa4793a44b41b797ae671b9/types/express/index.d.ts#L19
В основном используйте следующее:
declare module 'express-serve-static-core' {
interface Request {
myField?: string
}
interface Response {
myField?: string
}
}
Ответ 5
Ни одно из предложенных решений не помогло мне. В итоге я просто расширил интерфейс запроса:
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 = '';
}
Изменить: последние версии TypeScript жалуются на это. Вместо этого я должен был сделать:
someMiddleware(expressRequest: Request, res: Response, next: NextFunction): void
{
const req = expressRequest as RequestCustom;
req.property = '';
}
Ответ 6
В TypeScript интерфейсы открыты. Это означает, что вы можете добавлять к ним свойства из любого места, просто переопределяя их.
Учитывая, что вы используете этот express.d.ts файл, вы должны переопределить интерфейс Запрос для добавления дополнительного поля.
interface Request {
property: string;
}
Затем в вашей функции промежуточного программного обеспечения параметр req должен иметь это свойство. Вы можете использовать его без каких-либо изменений в вашем коде.
Ответ 7
Мои 2 цента: Расширьте текущий тип и код, как обычно.
import { Request, Response, Router } from 'express'
function handler(req: IRequest, res: Response, next: Function) {
const authId = req.authId
// ...
}
const router = Router()
router.get('/', handler) // no compiling problems
// this is just for ts, will disappear in transpilation
interface IRequest extends Request {
authId: string // example
}
Ответ 8
Одним из возможных решений является использование "двойного литья в любой"
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
Ответ 9
Хотя это очень старый вопрос, в последнее время я наткнулся на эту проблему. Принятый ответ работает хорошо, но мне нужно было добавить пользовательский интерфейс в Request
- интерфейс, который я использовал в своем коде, и который не очень хорошо работал с принятый ответ. Логически я попробовал это:
import ITenant from "../interfaces/ITenant";
declare namespace Express {
export interface Request {
tenant?: ITenant;
}
}
Но это не сработало, потому что .d.ts
рассматривает файлы .d.ts
как глобальный импорт, а когда они имеют импорт, они рассматриваются как обычные модули. Вот почему приведенный выше код не работает со стандартными настройками машинописи.
Вот что я в итоге делал
// typings/common.d.ts
declare namespace Express {
export interface Request {
tenant?: import("../interfaces/ITenant").default;
}
}
// interfaces/ITenant.ts
export interface ITenant {
...
}
Ответ 10
Может быть, на этот вопрос ответили, но я хочу поделиться немного,
теперь иногда интерфейс, как и другие ответы, может быть слишком ограничительным,
но на самом деле мы можем поддерживать требуемые свойства и затем добавлять любые дополнительные свойства для добавления, создав ключ с типом 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();
});
Итак, теперь мы можем добавить любое дополнительное свойство, которое мы хотим, к этому объекту.
Ответ 11
Если вы ищете решение, которое работает с express4, вот оно:
@types/express/index.d.ts: --------must be/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