我已经尝试了很长时间,老实说这不值得付出努力,但我仍然想看看是否有解决方案:
我正试图强制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',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 be
Article as well as that I need the second argument to be of type
{articleId:number} (or
未定义for array of articles). This is what
时应定义GetSignature`联合类型。
因此所需的用法类似于
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
提供type参数,但是我想知道是否有一种方法可以完成我在TS中描述的事情?