node.js - Kan inte komma åt headers i utökad Express.Request-typ


Jag försöker utöka Express Request för att exakt typa hur en query kommer att se ut. Jag gör för närvarande detta på följande sätt:

export interface TypedRequestQuery<T> extends Express.Request {
    query: T;
}

Detta fungerar till största delen, men vissa egenskaper verkar inte vara definierade. Till exempel:

(req as TypedRequestQuery<{data: string}>).headers

Fungerar inte. Det resulterar i följande fel:

Property 'headers' does not exist on type 'TypedRequestQuery<{ data: string; }>'

Jag har läst i flera källor att Express.Request är den korrekta typen för en requests args i en request handler. Men kanske missförstod jag? Att utelämna typningen av request handlern fungerar faktiskt!

router.get("/", async (req, res) => {
    req.headers["x-forwarded-for"] // no errors
})

Och headers-egenskapen finns i req.

Jag använder passport.js vilket jag märkte ändrar definitionen av Request (eller åtminstone utökar den). Inte säker på om detta är orsaken.

Min fråga är: Är Express.Request rätt typ att utöka härifrån? Om det är det, varför verkar gränssnittet ofullständigt och hur kan jag fixa detta? Om inte, vilken typ bör jag utöka från?

Svar #1

Express' begärans typ låter dig redan definiera frågetypen...

export interface Request<
    P = ParamsDictionary,
    ResBody = any,
    ReqBody = any,
    ReqQuery = ParsedQs, // 👈
    Locals extends Record<string, any> = Record<string, any>
> ...

Förfrågningstypen är den fjärde generiska, så du skulle behöva ange standardvärden för de första tre

import { ParamsDictionary, Request } from "express-serve-static-core";

type TypedRequestQuery<
  TQuery,
  TParams = ParamsDictionary,
  TResBody = any,
  TReqBody = any
> = Request<TParams, TResBody, TReqBody, TQuery>;

Då kan du använda det i dina rutter

router.get("/", async (req: TypedRequestQuery<{data: string}>, res) => {
  console.log("headers[x-forwarded-for]:", req.headers["x-forwarded-for"]);
  console.log("query[data]:", req.query.data);

  res.send("I wish Typescript would let us skip generics");
})

Ditt exempel misslyckas med kompilering eftersom du försöker åsidosätta query-egenskapen med en inkompatibel typ

error TS2430: Interface 'TypedRequestQuery<T>' incorrectly extends interface 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
  Types of property 'query' are incompatible.
    Type 'T' is not assignable to type 'ParsedQs'.

interface TypedRequestQuery<T> extends Request {
          ~~~~~~~~~~~~~~~~~

    interface TypedRequestQuery<T> extends Request {
                                ~
    This type parameter might need an `extends ParsedQs` constraint.

En kompatibel version skulle behöva ha din frågetyp utökad med ParsedQs

import { Request } from "express-serve-static-core";
import { ParsedQs } from "qs"

interface TypedRequestQuery<T extends ParsedQs> extends Request {
  query: T;
}