【发布时间】:2020-09-19 07:11:36
【问题描述】:
我现在尝试了很长时间,老实说这不值得,但我仍然想看看是否有解决方案:
我试图强制 TS 从元组中推断出我的函数签名。我尝试使用条件类型,但我似乎没有做对:
// model
interface User {
name: string
}
interface Article {
title: string
}
/// api
type Resource = 'user' | 'articles'
type Params = Record<string, number | string | boolean>
type GetSignature =
| ['user', undefined, User]
| ['articles', { articleId: number }, Article[]]
| ['articles', undefined, Article]
// get request
interface ObjArg {
resource: Resource
params?: Params
}
type RetType<TResult> = TResult & { cancel: () => void }
async function get<TResult>(args: ObjArg): Promise<RetType<TResult>>
async function get<TResult>(resource: Resource, params?: Params): Promise<RetType<TResult>>
async function get<TResult>(args: [ObjArg | Resource, Params?]): Promise<RetType<TResult>>{
const { resource, params } = typeof args[0] === 'object' ? args[0] : { resource: args[0], params: args[1] }
const result = await someAsyncFetch(resource, params)
return { ...result, cancel: () => { cancelAsyncFetch() }}
}
我希望 TS 能够从提供的参数中推断出 get 的签名,因此它会自动知道,例如调用 get('articles', { articleId: 1 }) the return type should beArticleas well as that I need the second argument to be of type{articleId: number}(orundefinedfor array of articles). This is whatGetSignature 时应该定义联合类型。
所以期望的用法是这样的
const user = get('user') // returns User
const article = get('articles', { articleId: 1 }) // returns Article
const articles = get('articles') // returns Article[]
我尝试了几十种方法,但似乎没有一种方法能提供我想要的界面。仅提及其中一个,我试图将签名作为类型参数 (get<TSignature exntends GetSignature>(...)) 并试图推断出所需的签名,如下所示:
resource: TSignature[0] extends infer T ? T : never
甚至
resource: TSignature[0] extends infer T ? Extract<GetSignature, T> : never
但似乎没有任何效果。现在我想我会坚持为TResult 提供类型参数,但我想知道是否有办法执行我在 TS 中描述的操作?
【问题讨论】:
标签: typescript generics tuples conditional-types