【问题标题】: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 谢谢你的评论。我编辑了我的示例以仅包含相关错误。

标签: typescript overloading union-types


【解决方案1】:

嗯,这是因为您提供的所有重载签名都不接受 string | null 作为 val 参数类型。从编译器的角度考虑这一点,在您的 A 接口中,您保证:

  1. method 可以接受null 并返回null
  2. method 可以接受string 并返回string

然后,您传入了 string | null 的联合 - 正如预期的那样,编译器抱怨没有 (val: string | null) => unknown(或类似的)签名(“没有重载匹配此调用”)。

错误消息告诉你编译器试图做什么:

  1. 检查(val: string) => string签名时将string | null分配给string
  2. 检查(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 作者提出这个问题可能也是一个好主意 - 这是编写重载的一种糟糕方式,因此他们绝对应该对类型进行更新。
猜你喜欢
  • 2021-06-05
  • 1970-01-01
  • 2016-08-27
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2021-11-01
  • 1970-01-01
  • 2020-01-03
相关资源
最近更新 更多