繁体   English   中英

typescript 交叉口类型 function

[英]typescript intersection types of function

我正在使用 typescript 并遇到了一些问题。 最简单的演示是:

type g = 1 & 2 // never
type h = ((x: 1) => 0) & ((x: 2) => 0) // why h not never
type i = ((x: 1 & 2) => 0)// why x not never

我不明白为什么类型h不是never而类型i中的 param x不是never

type e = (((x: 1) => 0) & ((x: 2) => 0)) extends (x: infer L) => 0 ? L : never; //  why e is 2 not never or 1?

另外,不明白为什么 type e2而不是never

注意:非原始类型通常用 UpperCamelCase 编写; 这将它们与原始类型和变量/属性名称区分开来。 我将在下面使用这个约定。

这个问题有很多部分,所以它的答案也会有很多部分。


让我们先解决简单的问题:

type G = 1 & 2 // never

microsoft/TypeScript#31838中实现了像1 & 2这样的空交叉点的减少,并随never 3.6 一起发布。 在此之前, 1 & 2的处理方式与never非常相似,因为您永远无法找到满足它的值。 1 & 2never之间实际上没有概念上的区别,尽管编译器实现细节可能会导致一个与另一个被区别对待。


下一个:

type I = ((x: 1 & 2) => 0) // why x not never

xnever ,但减少会延迟到您实际使用它:

type IParam = Parameters<I>[0]; // never

此延迟在microsoft/TypeScript#36696中实现,并与 TypeScript 3.9 一起发布。 在此之前, x被急切地简化为never像上面的G那样。


现在来看一些更复杂的例子:

type H = ((x: 1) => 0) & ((x: 2) => 0) // why H not never

实际上有很多原因H不是never

  • 特定于 TypeScript 的原因是因为 function 类型的交集被认为与具有多个调用签名的重载 function相同:

     declare const h: H; // 1/2 h(x: 1): 0 // 2/2 h(x: 2): 0 h(1); // okay h(2); // okay h(3); // error, no overload matches this call h(Math.random() < 0.5? 1: 2); // error, no overload matches this call

    注意h如何显示为具有两个重载的 function; 一个接受1参数,另一个接受2参数。 它不接受3 ,也不接受1 | 2 1 | 2即使从纯类型系统的角度来看它可能应该(参见microsoft/TypeScript#14107以获得支持这一点的长期功能请求)。

  • 即使 TypeScript 没有将函数交集解释为重载, H也不应该是never Function 类型的参数类型是逆变的(有关解释,请参阅我对此问题的回答。您还可以--strictFunctionTypes编译器标志的 TS 手册描述中阅读 function 参数的逆变性)。 逆变将事物变成它们的对 如果F<T>T中是逆变的,则F<T | U> F<T | U>等价于F<T> & T<U> ,而F<T & U>等价于F<T> | F<U> F<T> | F<U> 因此,一个一致的类型系统,当要求函数交集的参数类型时,将返回function参数类型的并集。 1 | 2 1 | 2不是never

  • 即使H一个完全无人居住的类型,目前 TypeScript 只是在特定情况下将交叉点减少到never ,功能交叉点不是其中之一。 如果您查看编译器源代码文件checker.ts ,它会显示“如果交叉类型包含类型never或多个单元类型或 object 类型和可空类型( nullundefined ),则认为它为空,或者类string类型和已知非string类型,或类number类型和已知非类number类型,或类symbol类型和已知非symbol类型 - void void 没有一个说“两个不兼容的 function 类型”,所以它没有减少到never


最后一个:

type E = (((x: 1) => 0) & ((x: 2) => 0)) extends (x: infer L) => 0 ? L : never;
//  why E is 2 not never or 1?

回想一下,函数的交集被认为是重载的 function。 TypeScript 的一个已知设计限制是,在对重载的 function 类型使用类型推断时,编译器不会尝试通过确定哪个调用签名与预期的推断最匹配来解决过载问题。 它只使用最后一个调用签名并忽略其中的所有 rest E中,这意味着编译器仅在与(x: infer L) => 0匹配时看到(x: 2) => 0 > 0 ,因此L被推断为2 “正确”的做法可能是联合1 | 2 1 | 2 ,但这不会发生。 有关此限制的一个实例,请参阅microsoft/TypeScript#27027


Playground 代码链接

如果

type h = ((x: 1) => 0) & ((x: 2) => 0)

您将1分配为x的类型,也称为文字类型。 文字类型几乎never最小的值集。 never和字面量类型1之间的区别在于, never是一个空集,但1集合中只有一个值。 所以never !== 1

这里

type i = (x: 1 & 2) => 0; 

参数x的类型never

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM