具有可选参数的函数,具体取决于函数的泛型类型

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

我正在尝试实现一个简约的类型安全函数,该函数可以针对类型化服务器 API 执行 HTTP 请求,但我正在与类型作斗争。具体来说,如何使第三个参数(HTTP 请求负载)对于

GET
DELETE
请求是可选的,同时对其进行验证并且对于
POST
PUT
是非可选的。

简化示例(TypeScript Playground):

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

我从来没有按照预期同时对所有四个条件进行类型检查。至少有一个总是坏掉的。

附注如果您想知道,playground 链接到完整的用例,这有点复杂。

typescript
1个回答
0
投票

您可以使用函数重载。

您创建一个可以在运行时处理任何情况的函数,然后为其提供许多充当不同重载的类型声明。

export type Method = 'GET' | 'DELETE' | 'POST' | 'PUT'

function httpRequest(method: 'GET' | 'DELETE', url: string, data?: Data): any;
function httpRequest(method: 'POST' | 'PUT', url: string, data: Data): any;
function httpRequest(method: Method, url: string, data?: Data) {
  return 'not implemented yet' as any
}

// expected usage:
interface Data {
  title: string;
}
httpRequest('POST', '/test', { title: 'test' }) // should typecheck
httpRequest('POST', '/test', { titleoops: 'test' }) // should not  typecheck
httpRequest('POST', '/test') // should not  typecheck
httpRequest('GET', '/test') // should typecheck

在调用站点,TS 将确保您的参数与其中一个重载相匹配。

© www.soinside.com 2019 - 2024. All rights reserved.