无法访问扩展的Express.Request类型中的标头

huangapple go评论66阅读模式
英文:

Can not access headers in extended Express.Request type

问题

我试图扩展Express的Request类型,以确切描述查询的外观。我目前是这样做的:

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

这在大部分情况下都可以工作,但有些属性似乎未定义。例如:

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

不起作用。它会产生以下错误:

属性'headers'在类型'TypedRequestQuery<{ data: string; }>'上不存在

我在多个来源中看到过,Express.Request是请求处理程序的请求参数的正确类型。但也许我理解错了?省略请求处理程序的类型注解确实起作用:

router.get("/", async (req, res) => {
    req.headers["x-forwarded-for"] // 没有错误
})

而且req中存在headers属性。

我正在使用passport.js,我注意到它更改了Request的定义(或至少是扩展了它)。不确定这是否是原因。

我的问题是:Express.Request是应该在此基础上进行扩展的正确类型吗?如果是,为什么接口看起来不完整,我应该如何解决这个问题?如果不是,我应该从哪种类型进行扩展?

英文:

I am trying to extend Express' Request to type exactly what a query will look like. I currently do this as follows:

export interface TypedRequestQuery&lt;T&gt; extends Express.Request {
    query: T;
}

This works for the most part, but some properties do not seem to be defined. For example:

(req as TypedRequestQuery&lt;{data: string}&gt;).headers

Does not work. It results in the following error:

Property &#39;headers&#39; does not exist on type &#39;TypedRequestQuery&lt;{ data: string; }&gt;&#39;

I have read in multiple sources that Express.Request is the correct type for a request handler's request argument. But maybe I misunderstood? Leaving out the typings of the request handler does work!:

router.get(&quot;/&quot;, async (req, res) =&gt; {
    req.headers[&quot;x-forwarded-for&quot;] // no errors
})

And the headers property is present in the req.

I am using passport.js which I noticed changes the definition of Request (or at least extends it). Not sure if this is the cause.

My question is: Is Express.Request the correct type to be extending from here? If it is, why does the interface seem incomplete and how can I fix this? If not, what type should I extend from?

答案1

得分: 1

Express的Request类型已经允许你定义查询类型...

export interface Request&lt;
    P = ParamsDictionary,
    ResBody = any,
    ReqBody = any,
    ReqQuery = ParsedQs, // &#128072;
    Locals extends Record&lt;string, any&gt; = Record&lt;string, any&gt;
&gt; ...

查询类型是第四个泛型参数,所以你需要为前三个提供默认值

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

type TypedRequestQuery&lt;
  TQuery,
  TParams = ParamsDictionary,
  TResBody = any,
  TReqBody = any
&gt; = Request&lt;TParams, TResBody, TReqBody, TQuery&gt;;

然后你可以在你的路由中使用它

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

  res.send(&quot;我希望Typescript能让我们跳过泛型参数&quot;);
})

你的示例编译失败,因为你尝试使用不兼容的类型覆盖query属性

error TS2430: Interface &#39;TypedRequestQuery&lt;T&gt;&#39; incorrectly extends interface &#39;Request&lt;ParamsDictionary, any, any, ParsedQs, Record&lt;string, any&gt;&gt;&#39;.
  Types of property &#39;query&#39; are incompatible.
    Type &#39;T&#39; is not assignable to type &#39;ParsedQs&#39;.

interface TypedRequestQuery&lt;T&gt; extends Request {
          ~~~~~~~~~~~~~~~~~

    interface TypedRequestQuery&lt;T&gt; extends Request {
                                ~
    This type parameter might need an `extends ParsedQs` constraint.

一个兼容的版本需要让你的查询类型扩展ParsedQs

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

interface TypedRequestQuery&lt;T extends ParsedQs&gt; extends Request {
  query: T;
}
英文:

Express' Request type already lets you define the query type...

export interface Request&lt;
    P = ParamsDictionary,
    ResBody = any,
    ReqBody = any,
    ReqQuery = ParsedQs, // &#128072;
    Locals extends Record&lt;string, any&gt; = Record&lt;string, any&gt;
&gt; ...

The query type is the 4th generic so you'd need to provide defaults for the first three

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

type TypedRequestQuery&lt;
  TQuery,
  TParams = ParamsDictionary,
  TResBody = any,
  TReqBody = any
&gt; = Request&lt;TParams, TResBody, TReqBody, TQuery&gt;;

Then you can use it in your routes

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

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

Your example fails compilation because you're trying to override the query property with an incompatible type

> none
&gt; error TS2430: Interface &#39;TypedRequestQuery&lt;T&gt;&#39; incorrectly extends interface &#39;Request&lt;ParamsDictionary, any, any, ParsedQs, Record&lt;string, any&gt;&gt;&#39;.
&gt; Types of property &#39;query&#39; are incompatible.
&gt; Type &#39;T&#39; is not assignable to type &#39;ParsedQs&#39;.
&gt;
&gt; interface TypedRequestQuery&lt;T&gt; extends Request {
&gt; ~~~~~~~~~~~~~~~~~
&gt;
&gt; interface TypedRequestQuery&lt;T&gt; extends Request {
&gt; ~
&gt; This type parameter might need an `extends ParsedQs` constraint.
&gt;

A compatible version would need to have your query type extend ParsedQs

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

interface TypedRequestQuery&lt;T extends ParsedQs&gt; extends Request {
  query: T;
}

huangapple
  • 本文由 发表于 2023年3月31日 19:13:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897888.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定