如何在TypeScript中将兼容的并集类型从一个重载函数传递到另一个



我有两个函数,每个函数都以一个并集类型作为输入,其输出与输入的类型匹配。其中一个函数调用另一个函数。我相信我应该能够使用重载类型定义来表示它,比如:

function f1(input: number): number;
function f1(input: string): string;
function f1(input: string | number): string | number {
return input;
}
function f2(input: number): number;
function f2(input: string): string;
function f2(input: string | number): string | number {
return f1(input);
}

然而,这会导致类型错误:

No overload matches this call.
Overload 1 of 2, '(input: number): number', gave the following error.
Argument of type 'string | number' is not assignable to parameter of type 'number'.
Type 'string' is not assignable to type 'number'.
Overload 2 of 2, '(input: string): string', gave the following error.
Argument of type 'string | number' is not assignable to parameter of type 'string'.
Type 'number' is not assignable to type 'string'.(2769)

是否有其他方法可以正确地表示这些函数保留其输入类型?重载类型是可行的吗?或者我可以以某种方式使用泛型来实现这一点吗?

TypeScript不会从重载的调用签名中自动合成联合上的调用签名。有一个长期存在的问题,microsoft/TypeScript#114107,要求这样做,但我不确定它是否会实现。现在,你必须做"其他事情",其中包括任何数量的变通方法:


一个解决方法是添加您希望看到的联合调用签名:

function f1(input: number): number;
function f1(input: string): string;
function f1(input: string | number): string | number; // added
function f1(input: string | number): string | number {
return input;
}
function f2(input: number): number;
function f2(input: string): string;
function f2(input: string | number): string | number {
return f1(input); // okay
}

另一种解决方法是使用条件类型和泛型来用单个调用签名替换重载:

function f1<T extends number | string>(input: T): T extends number ? number : string;
function f1(input: string | number): string | number {
return input;
}
function f2(input: number): number;
function f2(input: string): string;
function f2(input: string | number): string | number {
return f1(input); // okay
}

另一种解决方法是在调用f1()时使用条件逻辑,使其参数仅为stringnumber,而从不为string | number:

function f2(input: number): number;
function f2(input: string): string;
function f2(input: string | number): string | number {
return typeof input === "number" ? f1(input) : f1(input); // okay
}

最后,最终的解决方法是使用类型断言:

function f2(input: number): number;
function f2(input: string): string;
function f2(input: string | number): string | number {
return f1(input as any) as string | number; // make it work
}

解决方案代表了复杂性、冗余性和类型安全性之间的权衡。我相信还有其他解决办法;这取决于您来决定哪一个(如果有的话(最适合您的用例。无论如何,希望这会有所帮助;祝你好运

游乐场链接到代码

添加并集重载可以完成以下操作:函数f1(输入:字符串|数字(:字符串|数量;

function f1(input: number): number;
function f1(input: string): string;
function f1(input: string | number): string | number;
function f1(input: string | number): string | number {
return input;
}
function f2(input: number): number;
function f2(input: string): string;
function f2(input: string | number): string | number {
return f1(input);
}
const resultF2Num = f2(12);     // Number
const resultF2Str = f2('12');   // String
const resultF1Num = f1(12);     // Number
const resultF1Str = f1('12');   // String

我找到了一种似乎有效的方法,通过将重载定义为条件类型:


function f1<T extends string | number>(input: T): T extends string ? string : number;
function f1(input: string | number): string | number {
return input;
}
function f2<T extends string | number>(input: T): T extends string ? string : number
function f2(input: string | number): string | number {
return f1(input);
}
const testValid1: string = f2('some string');
const testValid2: number = f2(42);
const testInvalid: number = f2('not a number');

相关内容

最新更新