我具有以下通用功能:
export function useClientRequest<T, R extends (...args: any) => AxiosPromise<T>>(
func: R,
...args: Parameters<R>
): [T | undefined, boolean, AxiosError | undefined] {
// Irrelevant
}
概括地说,函数的返回值包含类型T的值,该值应如上所述进行推断。
然后,我尝试如下使用它:
interface Foo {
// ...
}
function fooGetter(url: string): AxiosPromise<Foo> {
return Axios.get<Foo>(url);
}
const [data] = useClientRequest(fooGetter, 'url.com');
但是我的IDE报告说
data
是unknown
类型的,因为T
被推断为unknown
。我做错什么了吗,或者这是TypeScript的限制?
typescript v3.7.2
我知道我可以指定类型参数。我想知道为什么会错误地推断出它们,以及是否可以通过某种方式更改实现以帮助推断机制。
最佳答案
从TypeScript specifications:
有了您的功能签名,
<T, R extends (...args: any) => AxiosPromise<T>>(
func: R, ...args: Parameters<R>
): [T | undefined, boolean, AxiosError | undefined]
,我对以上陈述的解释是,
T
出现在参数extends (...args: any) => AxiosPromise<T>
的类型参数约束签名R
中,因此无法正确解析。 unknown
只是泛型类型参数的implicit default constraint type。因此,这些人为的示例将起作用:
declare function fn0<T, U extends T>(fn: (t: T) => U): U
const fn0Res = fn0((arg: { a: string }) => ({ a: "foo", b: 42 })) // {a: string; b: number;}
declare function fn1<T, F extends (args: string) => number>(fn: F, t: T): T
const fn1Res = fn1((a: string) => 33, 42) // 42
在接下来的两个示例中,编译器将
T
推断为unknown
,因为T
仅在U
的调用签名约束中引用,而未在函数参数代码位置中用于进一步的编译器提示:declare function fn2<T, U extends (args: T) => number>(fn: U): T
const fn2Res = fn2((arg: number) => 32) // T defaults to unknown
declare function fn3<T, U extends (...args: any) => T>(fn: U): T
const fn3Res = fn3((arg: number) => 42) // T defaults to unknown
可能的解决方案(选择最合适的解决方案)
1.)您可以仅为函数参数和返回类型引入类型参数
T
和R
:declare function useClientRequest2<T, R extends any[]>(
func: (...args: R) => Promise<T>,
...args: R
): [T | undefined, boolean, AxiosError | undefined]
const [data] = useClientRequest2(fooGetter, 'url.com'); // data: Foo | undefined
2.)这是带有条件类型的替代方法(更为冗长):
declare function useClientRequestAlt<R extends (...args: any) => Promise<any>>(
func: R,
...args: Parameters<R>
): [ResolvedPromise<ReturnType<R>> | undefined, boolean, AxiosError | undefined]
type ResolvedPromise<T extends Promise<any>> = T extends Promise<infer R> ? R : never
const [data2] = useClientRequestAlt(fooGetter, 'url.com'); // const data2: Foo | undefined
Playground
关于typescript - TypeScript-泛型被错误地推断为未知,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58779360/