node.js - Δεν είναι δυνατή η πρόσβαση στους headers στον επεκταμένο τύπο Express.Request


Προσπαθώ να επεκτείνω το Request του Express για να καθορίσω ακριβώς πώς θα μοιάζει ένα query. Αυτό το κάνω επί του παρόντος ως εξής:

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

Αυτό λειτουργεί κατά κύριο λόγο, αλλά κάποιες ιδιότητες φαίνεται να μην έχουν οριστεί. Για παράδειγμα:

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

Δεν λειτουργεί. Προκαλεί το ακόλουθο σφάλμα:

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

Έχω διαβάσει σε πολλές πηγές ότι το Express.Request είναι ο σωστός τύπος για το όρισμα request ενός διαχειριστή αιτήσεων. Αλλά ίσως να κατάλαβα λάθος; Η παράλειψη των τύπων του διαχειριστή αιτήσεων λειτουργεί όντως!:

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

Και η ιδιότητα headers υπάρχει στο req.

Χρησιμοποιώ το passport.js, το οποίο παρατήρησα ότι αλλάζει τον ορισμό του Request (ή τουλάχιστον τον επεκτείνει). Δεν είμαι σίγουρος αν αυτό είναι η αιτία.

Η ερώτησή μου είναι: Είναι το Express.Request ο σωστός τύπος για να επεκτείνω από εδώ; Αν είναι, γιατί η διεπαφή φαίνεται ελλιπής και πώς μπορώ να το διορθώσω; Αν όχι, από ποιον τύπο θα πρέπει να επεκταθώ;

Απάντηση #1

Ο τύπος αιτήματος του Express σάς επιτρέπει ήδη να ορίζετε τον τύπο ερώτησης...

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

Ο τύπος ερωτήματος είναι ο 4ος γενικός, οπότε θα χρειαστεί να παρέχετε προκαθορισμένες τιμές για τους πρώτους τρεις

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

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

Τότε μπορείτε να το χρησιμοποιήσετε στις διαδρομές σας

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

Το παράδειγμά σας αποτυγχάνει στη σύνταξη επειδή προσπαθείτε να αντικαταστήσετε την ιδιότητα query με έναν μη συμβατό τύπο

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.

Μια συμβατή έκδοση θα χρειάζεται να έχει τον τύπο του ερωτήματός σας να επεκτείνει το ParsedQs

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

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