gpt4 book ai didi

typescript - 递归中断了对重载函数的类型检查

转载 作者:行者123 更新时间:2023-12-05 03:17:44 24 4
gpt4 key购买 nike

鉴于以下非常相似的功能:

function transform1 <T extends string>(value: T): T;
function transform1 <T extends string>(value: T[]): T[]; // error, can't return 0
function transform1 <T extends string>(value: T | T[]) {
if (Array.isArray(value)) {
return 0;
} else {
return value[0];
}
}

function transform2 <T extends string>(value: T): T;
function transform2 <T extends string>(value: T[]): T[];
function transform2 <T extends string>(value: T | T[]) {
if (Array.isArray(value)) {
return 0; // ok somehow?
} else {
return transform2([value])[0];
}
}

为什么对于第二个,我没有收到关于返回 0 的警告?唯一的区别是在第二个中我再次调用 transform2(递归)。忽略此调用将在运行时中断的事实,因为将返回 0 并且 0[0]undefined

为什么递归会阻止 TypeScript 检查它?我不得不在这里显式注释函数返回类型:

function transform2 <T extends string>(value: T | T[]): T | T[] {

Playground

最佳答案

overloaded 的类型检查函数语句有点奇怪而且没有很好的记录。将调用签名集与实现签名进行比较,如果编译器认为它们彼此之间没有足够的“相关性”,则会发出错误(尽管不是非常有用的错误,参见 ms/TS#48186 )。

在您的示例代码中,编译器必须从实现主体推断实现返回类型。对于 transform1,它推断出 string | 0(您可以通过将实现复制到新函数并查看推断的返回类型来验证),因为我认为 value[0] 正在获取字符串的字符。对于 transform2,它推断出 T | 0(同样,可通过复制验证),因为 value 缩小为 T,并且 transform2([value]) 返回 T[],索引为T

这意味着,从类型检查器的角度来看,这些是您的函数:

function transform1<T extends string>(value: T): T;
function transform1<T extends string>(value: T[]): T[] // error!
function transform1<T extends string>(value: T | T[]): string | 0 {
throw new Error()
}

function transform2<T extends string>(value: T): T;
function transform2<T extends string>(value: T[]): T[];
function transform2<T extends string>(value: T | T[]): T | 0 {
throw new Error()
}

(所以递归在这里有点转移注意力。)

第一个错误是因为string | 0 未被视为与 T | 正确“相关” T[],而第二个是可以接受的,因为 T | 0 视为与 T | 正确“相关” T[]。我真的不知道为什么;对于第一个,显然 T[] 不可能是 string0,因为 T extends string .对于第二个,由于同样的原因,T[] 不可能是 string0 似乎同样不可能。这意味着编译器并没有真正使用这种逻辑来允许/禁止调用签名。我猜测泛型的存在导致编译器更加宽松并且不去检查 TT[] 是否兼容.

在寻找权威答案时,我在 microsoft/TypeScript#44661 重新发现了一个有点相关的问题,其中,当被问及将重载调用签名与实现进行比较的规则时,@RyanCavanaugh said :

The rules are a mess of backcompat that no one wanted to write down.

Basically the idea is to detect totally wrong situations and not too much else extra, keeping in mind the limitation that we're analyzing the function body opaquely.

所以这是我能得到的最接近答案:string | 0 对于 T[] 是“完全错误的”,而 T | 0 显然不是“完全错误”,至少在编译器对“错误”的粗略检查可以检测到的范围内。

Playground link to code

关于typescript - 递归中断了对重载函数的类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73993267/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com