我正在尝试实现一个极简的类型安全函数,该函数针对类型化的服务器 API 执行 HTTP 请求,但类型问题让我很头疼。具体来说,如何使第三个参数(HTTP 请求负载)对于GET
和请求为可选,同时对于和DELETE
为经过验证且非可选。POST
PUT
一个简化的示例(TypeScript 游乐场):
export type Method = 'GET' | 'DELETE' | 'POST' | 'PUT'
// attempt 1:
const httpRequest1 = <M, D>(method: M, url: string, data?: D) =>
'not implemented yet' as any
// attempt 2:
type HttpRequest <M extends Method, D, R=unknown> = M extends 'GET' | 'DELETE'
? (method: M, url: string) => Promise<R>
: (method: M, url: string, data: D) => Promise<R>
const httpRequest2: HttpRequest = (method, url, data) =>
'not implemented yet' as any
// expected usage:
interface Data {
title: string;
}
httpRequest<'POST', Data>('POST', '/', { title: 'test' }) // should typecheck
httpRequest<'POST', Data>('POST', '/', { titleoops: 'test' }) // should NOT typecheck
httpRequest<'POST', Data>('POST', '/') // should NOT typecheck
httpRequest<'GET', undefined>('GET', '/') // should typecheck
我从来没有同时按照预期对全部四个条件进行类型检查。至少有一个条件总是不成立。
编辑:如果您好奇,完整的用例,已使用工作解决方案进行了更新。
您可以使用函数重载。
您创建一个可以在运行时处理任何情况的函数,然后为其提供多个充当不同重载的类型声明。
在调用点,TS 将确保您的参数与其中一个重载匹配。
你可以使用扩展语法来代替函数重载:
操场