web-dev-qa-db-ja.com

Typescriptを使用してExpress Requestオブジェクトを拡張する

TypeScriptを使用してミドルウェアからのリクエストオブジェクトを表現するプロパティを追加しようとしています。ただし、オブジェクトに追加のプロパティを追加する方法がわかりません。可能であれば、ブラケット表記を使用しないことを希望します。

私はこれに似たものを書くことを可能にするソリューションを探しています(可能であれば):

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

カスタム定義を作成し、TypeScriptの Declaration Merging という機能を使用します。これは一般的に使用されています。 in method-override

ファイルcustom.d.tsを作成し、もしあればtsconfig.jsonfiles-セクションに含めるようにしてください。内容は次のようになります。

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

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でさらに詳しく

47
basarat

受け入れられた答え(他の人として)は私にはうまくいきませんが、

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

した。それが誰かを助けることを願っています。

17
max-lt

提供されたソリューションはどれも私にとってはうまくいきませんでした。私は単にRequestインターフェースを拡張することになりました:

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 = '';
}
9
Tom Mettam

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
  }
}
9
JCM

TypeScriptでは、インターフェースはオープンエンドです。つまり、プロパティを再定義するだけで、どこからでもプロパティを追加できます。

この express.d.ts ファイルを使用していることを考慮すると、Requestインターフェースを再定義して、余分なフィールド。

interface Request {
  property: string;
}

ミドルウェア関数では、reqパラメーターにもこのプロパティが必要です。コードを変更せずに使用できるはずです。

8
toskv

可能な解決策の1つは、「二重キャスト」を使用することです

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

2
Bruno Grieder

これは非常に古い質問ですが、最近この問題に出くわしました。受け入れられた答えは問題なく動作しますが、カスタムインターフェイスをRequestに追加する必要がありました。受け入れられた答えでとてもよく。論理的に、私はこれを試しました:

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

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

しかし、TypeScriptは.d.tsファイルをグローバルインポートとして処理し、インポートがある場合は通常のモジュールとして処理されるため、それは機能しませんでした。そのため、上記のコードは標準のTypeScript設定では機能しません。

これが私がやったことです

// typings/common.d.ts

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

export interface ITenant {
    ...
}
2
16kb