Подтвердить что ты не робот

Extend Express Request с помощью Typescript

Я пытаюсь добавить свойство для выражения объекта запроса из промежуточного программного обеспечения с помощью typescript. Однако я не могу понять, как добавить дополнительные объекты к объекту. Идентификатор предпочитает, если возможно, использовать нотацию с кронштейном.

Im ищет решение, которое позволило бы мне написать что-то похожее на это (если возможно):

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

Ответ 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