接口的重载方法不能接受联合类型:“没有重载匹配此调用”
Posted
技术标签:
【中文标题】接口的重载方法不能接受联合类型:“没有重载匹配此调用”【英文标题】:Overloaded method of an interface cannot accept a union type: "No overload matches this call" 【发布时间】:2021-05-26 16:54:11 【问题描述】:我使用了一个第 3 方库,它定义了一个接口 (A
) 和一个重载方法 (method
)。该方法可以接受空值或字符串值作为参数。
我定义了一个联合类型:string | null
,并将它作为参数传递给方法,但我得到一个错误:
No overload matches this call.
Overload 1 of 2, '(val: null): null', gave the following error.
Argument of type 'StringOrNull' is not assignable to parameter of type 'null'.
Type 'string' is not assignable to type 'null'.
Overload 2 of 2, '(val: string): string', gave the following error.
Argument of type 'StringOrNull' is not assignable to parameter of type 'string'.
Type 'null' is not assignable to type 'string'.(2769)
这是我的代码: TypeScript Playgroud
interface A
method(val: null): null;
method(val: string): string;
type StringOrNull = string | null;
function myFunc(obj: A, val: StringOrNull)
obj.method(val); // Error: No overload matches this call.
为什么会发生这种情况,我该如何解决?
【问题讨论】:
我在你的例子中有三个错误。你能解决它吗? @captain-yossarian 谢谢你的评论。我编辑了我的示例以仅包含相关错误。 【参考方案1】:嗯,这是因为您提供的所有重载签名都不接受 string | null
作为 val
参数类型。从编译器的角度考虑这一点,在您的 A
接口中,您保证:
method
可以接受null
并返回null
method
可以接受string
并返回string
然后,您传入了 string | null
的联合 - 正如预期的那样,编译器抱怨没有 (val: string | null) => unknown
(或类似的)签名(“没有重载匹配此调用”)。
错误消息告诉你编译器试图做什么:
-
检查
(val: string) => string
签名时将string | null
分配给string
检查(val: null) => null
签名时将string | null
分配给null
如您所见,val
的两种类型都与StringOrNull
联合不兼容。我认为在这种情况下(坦率地说,总的来说)写一个受约束的泛型比函数重载更好(此外,你的方法是identity function):
interface A
method<T extends StringOrNull>(val: T) : T;
type StringOrNull = string | null;
function myFunc(obj: A, val: StringOrNull)
obj.method(val); //OK
Playground
顺便说一句:手册 2.0 在article about overloads 中专门解决了这个陷阱:
TypeScript 只能将函数调用解析为单个重载
来自 cmets 讨论的第二条注释:如果您不控制 A
接口的声明,您可以利用 declaration merging 技术来提供您自己的签名:
interface A
method(val: string) : string;
interface A
method<T extends StringOrNull>(val: T) : T;
type StringOrNull = string | null;
function myFunc(obj: A, val: StringOrNull)
obj.method(val); //OK
如果接口是从模块中导入的,则必须使用上述与module augmentation配对。
【讨论】:
感谢您的回答。你有我的赞成票。不幸的是,我无法控制interface A
。它来自我使用的一个库(我在我的问题中指出了它)。您对如何更改myFunc
注释有什么建议吗?
@SergeyGoliney - 好吧(顺便说一句,你可能应该提到你不能更改接口本身) - 你可以利用接口合并并使用该方法的通用版本再次声明 A
- 他们应该合并,你会得到你需要的 - 我很快就会添加一个到操场的链接
我看到的另一种方法是扩展接口,如果你不喜欢合并,但我认为如果你不控制接口的定义方式,你就无能为力了
如果库是一个模块,上面提到的可以用module augmentation补充以使事情正常工作(除非A
是默认导出-在这种情况下你搞砸了,必须修补界面随时使用)
@SergeyGoliney - NP。向 3P lib 作者提出这个问题可能也是一个好主意 - 这是编写重载的一种糟糕方式,因此他们绝对应该对类型进行更新。以上是关于接口的重载方法不能接受联合类型:“没有重载匹配此调用”的主要内容,如果未能解决你的问题,请参考以下文章