假设我下面有一些代码:
type Func1<T1> = (arg1: T1) => any;
type FuncArray<T1> = (arg1: T1, b: string) => any
interface Callable {
<T>(fn: Func1<T>, arg1: T): string
<T1>(fn: FuncArray<T1>, arg1: T1): number
}
const call: Callable = (...args: any): any => { }
interface Config {
url?: string
headers?: { [K: string]: string | number }
}
interface Requests {
(config: Config): string
(url: string, config?: Config): string
}
const request: Requests = (url: string | Config, config?: Config) => '123'
const h = call(request, {}) // error: Argument of type 'Requests' is not assignable to parameter of type 'FuncArray<string>'.
// Types of parameters 'config' and 'arg1' are incompatible.
// Type 'string' has no properties in common with type 'Config'.
该错误表明call
正在使用其第二个过载签名,我认为在此特定情况下它将使用其第一个过载。
我的理解是request
应该匹配Requests
第一次重载,然后call(request, {})
匹配Callable
第一次重载,但实际上不匹配。我在哪里弄错了?
所以我的问题是为什么call(request, {})
与<T>(fn: Func1<T>, arg1: T): string
不匹配?
答案 0 :(得分:1)
此问题与Callable
的重载无关。您可以通过注释掉第二个重载来自己查看:
interface Callable {
<T>(fn: Func1<T>, arg1: T): string
//<T1>(fn: FuncArray<T1>, arg1: T1): number
}
然后您看到错误:
const h = call(request, {}) // error!
// -------------------> ~~
// Argument of type '{}' is not assignable to parameter of type 'string'.
因此,编译器查看了request
并推断出T
的类型为string
,然后{}
与string
不匹配,您会得到一个错误。因此,问题在于编译器不接受call(request, {})
作为Callable
的第一个重载的匹配项。
如果取消注释Callable
的第二次重载,编译器会发现它也不匹配第二次重载,并且错误更改为“此调用没有重载”。因此,不必担心FuncArray
。
那么call(request, {})
为什么不匹配第一个Callable
重载?
问题在于 Requests
是一个重载的函数接口,并且是generic type parameter inference cannot do overload resolution at the same time。这是TypeScript的设计限制。当编译器看到call(request, {})
时,它必须推断T
的类型。 它没有选择确定应该Requests
的两个重载中的哪个重载,而是选择了最后一个。并且(url: string, config?: Config)=> string
与Func1<string>
相匹配。一切都从那里出错。
那你该怎么办?最简单的方法是手动指定泛型参数,以减轻编译器进行推断的负担:
const h = call<Config>(request, {}) // okay
一旦指定T
为Config
,编译器 then 就可以对request
进行重载解析,并验证是的,request
是有效的Func1<Config>
。同样,您可以通过类型断言将request
的类型扩展为Func1<Config>
,以便正确推断T
:
const i = call(request as Func1<Config>, {}); // okay
这两种方法都应该起作用。
好的,希望能有所帮助;祝你好运!