【问题标题】:Function wrapper statically checking parameters for HTTP response函数包装器静态检查 HTTP 响应的参数
【发布时间】:2021-12-25 15:04:24
【问题描述】:

我正在尝试为调用 Express'es 链 res.status(..).json(..) 的函数实现类型断言包装器。我想我“已经在那里”,但我卡住了。目标是静态检查是否:

  • 传递的 HTTP 状态代码符合特定的响应负载
  • 响应载荷具有一定的价值

TypeScript Playground 演示(完整实现尝试): click

其中一个错误来自我在上面链接的 TS 演示代码 [x] 中收到的列表:

类型“THTTPStatusCodeToData”上不存在属性“200”

包装器实现是:

function responseWrapper<
  DataKey extends keyof IEmbracedResponse
>(
  res: Res,
  status: keyof typeof mappedHTTPStatusCode,
  data: Record<
    DataKey, 
    THTTPStatusCodeToData[typeof status] // <-- so far, problem is here [x]
  >
) {
  return res.status(status).json(data); // just a chain call, but TS asserts correct `data` type for certain `status`
}

使用示例:

router.get('/', (req: Request, res: Response) => {
  if (!req.body.login) {
     return responseWrapper(res, 400, { error: 'Request payload lacks of "login"!' });
  }

  return responseWrapper(res, 200, { payload: { isAdmin: true }});
})

示例输入和 TS 预期类型检查结果:

responseWrapper(res, 200, { exception: Error('ups') }); // <-- fail, because 'exception' key cannot be associated with 200 status
responseWrapper(res, 500, { exception: 'something crashed'}); // <-- fail, because 'exception' cannot be a string, but Error object
responseWrapper(res, 200, { something: null}); // <-- fail, because status 200 cannot be associated with 'something' key
responseWrapper(res, 500, { error: 'ups' }); // <-- fail, because status 500 must be associated with 'exception' key, not the 'error' key

responseWrapper(res, 200, { payload: { isAdmin: true }}); // <-- ok, because status 200 can be associated with 'payload' key and the payload has object value
responseWrapper(res, 500, { exception: Error('ups') }); // <-- ok, because status 500 can be associated with 'exception' key and the value is Error object
responseWrapper(res, 400, { error: 'ups' }); // <-- ok, because status 400 can be associated with 'error' key and it's a string

到目前为止,我使用了不太高级的包装器,只是为了检查传递的对象值是否与键正确关联,但现在我还希望获得关于值关联检查的 HTTP 状态:

const embraceResponse = <
  Key extends keyof IEmbracedResponse
>(response: Record<Key, IEmbracedResponse[Key]>) =>
  response;

// usage examples:
res.status(200).json(embraceResponse({ payload: { prop: true } }));
res.status(400).json(embraceResponse({ error: 'ups' }));

【问题讨论】:

    标签: typescript response wrapper http-status-codes payload


    【解决方案1】:

    感谢完全正常工作的游乐场 :),我对您的代码进行了一些更改,关键更改是一种将状态转换为数据的实体类型。 responseWrapper 定义变得更简单。而且,您提供的支票现在似乎可以正常工作了。

    type StatusToData<status> = 
      status extends keyof TypeOfHTTPStatusCodes['SUCCESSFUL'] ? Pick<IEmbracedResponse,'payload'> | Pick<IEmbracedResponse,'message'>
      : status extends keyof TypeOfHTTPStatusCodes['CLIENT_ERROR'] ? Pick<IEmbracedResponse, 'error'> 
      : status extends keyof TypeOfHTTPStatusCodes['SERVER_ERROR'] ? Pick<IEmbracedResponse, 'exception'>
      : never;
    
    function responseWrapper<
       Status extends keyof typeof mappedHTTPStatusCode
    >(
      res: Res,
      status: Status ,
      data: StatusToData<Status>,
    ) {
      return res.status(status).json(data); 
    }
    

    Full Code in playground

    【讨论】:

    猜你喜欢
    • 2021-04-14
    • 1970-01-01
    • 2014-09-08
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    相关资源
    最近更新 更多