typescript 没有重载匹配,但类型正确

xuo3flqw  于 2023-03-04  发布在  TypeScript
关注(0)|答案(1)|浏览(496)

我有一个重载函数f,有两个可能的参数:

const f: {
  (x: number): void;
  (x: string): void;
} = (x: number | string) => {};

......以及应该传递给函数f的值的数组arr

const arr = [1, "1"];

...当类型正确时,打印脚本日志:

f(1);      // works
f("1");    // works

f(arr[0]); // error: No overload matches this call.

为什么它显示这个错误,即使函数f可以接受number | string可能值中的numberstring

rslzwgfq

rslzwgfq1#

您遇到了TypeScript长期缺失的功能;请参阅microsoft/TypeScript#14107中的相关特性请求。当您调用重载函数时,编译器当前只能将调用解析为该函数的一个调用签名。它不会尝试合并调用签名或将调用解析为多个签名。因此,即使 * 概念上 *使用联合类型X | Y的参数调用{(x: X): A; (y: Y): B;}应该是可接受的,并且返回A | B类型的值,编译器不执行此类分析。
根据TypeScript程序管理器的评论,目前还没有这样做,因为你不能只对所有重载函数这样做,例如,允许像{(xy: X | Y, tu: T| U): A | B}一样调用{(x: X, t: T): A; (y: Y, u: U): B}是一个错误,因为你不应该被允许为第一个参数传入X,为第二个参数传入U。我们必须检测到只有一个参数类型不同的多个调用签名的情况,并将它们组合起来,但根据评论,这可能不优雅,可能代价高昂,而且可能有奇怪的边缘情况。
这就是问题的答案如果你想看到这种情况发生,你可能想👍在GitHub中给特性请求一个,但是它不太可能改变太多。
您并没有问应该怎么做,但是在实现之前,建议的解决方案是添加另一个重载调用签名,它接受您想要的内容:

const f: {
    (x: number): void;
    (x: string): void;
    (x: number | string): void; // <-- add this
} = (x: number | string) => { };

const arr = [1, "1"];

f(1);      // works
f("1");    // works
f(arr[0]); // works

尽管在上面的例子中,由于前两个调用签名都返回void,所以没有理由再使用它们。如果它们返回不同的类型,那么您可能仍然需要三个调用签名。
如果你的底层用例不允许你重新定义函数类型,那么你必须用某种方法来解决它,比如Assertf接受你传递的参数:

(f as (x: number | string) => void)(arr[0]); // works

Playground代码链接

相关问题