函数包装器静态检查 HTTP 响应的参数
Posted
技术标签:
【中文标题】函数包装器静态检查 HTTP 响应的参数【英文标题】:Function wrapper statically checking parameters for HTTP response 【发布时间】:2021-12-25 15:04:24 【问题描述】:我正在尝试为调用 Express'es 链 res.status(..).json(..)
的函数实现类型断言包装器。我想我“已经在那里”,但我卡住了。目标是静态检查是否:
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' ));
【问题讨论】:
【参考方案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
【讨论】:
我最终搞砸了,但它似乎奏效了。 github.com/ScriptyChris/Fake-PEV-Shopping/blob/…以上是关于函数包装器静态检查 HTTP 响应的参数的主要内容,如果未能解决你的问题,请参考以下文章