在 ExpressJs 中覆盖请求参数时出错

问题描述 投票:0回答:1

我正在使用express

4.19.2
(撰写本文时最新)

这是

Request
泛型类型声明

interface ParamsDictionary {
  [key: string]: string;
}

interface Request<
  P = core.ParamsDictionary,
  ResBody = any,
  ReqBody = any,
  ReqQuery = core.Query,
  Locals extends Record<string, any> = Record<string, any>,
> extends core.Request<P, ResBody, ReqBody, ReqQuery, Locals> {}

我正在尝试覆盖 P 或 Params,以便我可以在路由处理程序中引用实际类型。但是,我收到此错误

Type '(req: Request<ItemParam, unknown, ItemBody, unknown, JwtUser>, res: Response, next: NextFunction) => Promise<void>' is not assignable to type 'RequestHandler<ParamsDictionary, unknown, ItemBody, ParsedQs, JwtUser>'

Types of property 'params' are incompatible. Property 'itemId' is missing in type 'ParamsDictionary' but required in type 'ItemParam'

我的代码片段

interface ItemParam {
  itemId: string;
}

const myHandler = async (
    // ✅ No typescript error here
    req: Request<ItemParam, unknown, ItemBody, unknown, JwtUser>,
    res: Response,
    next: NextFunction,
  ): Promise<void> => {
   const { itemId } = req.params; // ✅ Can refer itemId
   const { amount } = req.body; // ✅ Can refer amount
};

// ❌ However, I get the error in the route
router.route('/:itemId').put(
  validate({
    params: {
      itemId: Joi.string().required(),
    },
  }),
  myHandler, // ❌ Error here as shown above
);

如果删除验证,我不会收到任何 ts 错误

// ✅ This works
router.route('/:itemId').put(
      myHandler,
    );

如果我像这样重写我的处理程序,我也不会收到错误

// ✅ This works
Request<{ itemId: string }, unknown, PlaceBidItemBody, unknown, JwtUser>

我可以采用上述方法作为解决方法。但是有人可以帮助我理解这个问题或确认这是否是一个明确的错误吗?

更新/可能的解决方案 我将 ItemParam 类型固定为:

interface ItemParam {
  itemId: string;
  [key: string]: string;
}

我不能/不想从

ParamsDictionary
扩展,因为它来自
express-server-static-code
,它预先包含在
express
中。据我所知,从您未明确安装的软件包中引用任何内容都不是一个好习惯。

无论如何,有人可以帮助我理解为什么原来的

ItemParam
ParamsDictionary
不容易兼容吗?

typescript express
1个回答
0
投票

做了一些挖掘来理解和审查规则。这里有一些提醒我:

  1. itemId
    是文字类型。不是字符串类型,不是数字类型,而是文字类型。由于名称本身,它是一个字符串,但它并不使其成为一个字符串。同样,我们不能将任何字符串值分配给这种类型。 例如
type Status = 'success' | 'failed'
const status1: Status = 'error'; ❌
const status2: Status = 'success'; ✅

这是非常基础的,我知道这一点,但我想直到现在还不完全。或者很可能我对

Body
如何接受接口而着迷,但不知道
Param
(也是
Query
)。我希望我的代码整洁干净,并且我的接口/类型可重用。

  1. 为了进一步自学,
    Param
    Query
    Body
    之间的类型差异和限制背后的原因在于浏览器的工作方式——属性值始终是字符串,与可以传递数字的
    Body
    不同、布尔值,甚至除了字符串之外还可以为 null。

Param,param

id
的值将始终被视为字符串
"1000678"

http://example.com/api/sample/:id
http://example.com/api/sample/1000678

查询,查询变量

id
的值将始终被视为字符串

http://example.com/api/sample?id=1000678

Body通过Post/Put,

id
的值可以是数字,并且将被视为数字

{
   "id": 1000678,
}

解决方案这确保了键的类型为字符串,同时保留了接口的强类型性。

interface ItemParam extends Record<string, string> {
  itemId: string;
}

interface ItemParam {
  itemId: string;
  [key: string]: string;
}
© www.soinside.com 2019 - 2024. All rights reserved.