简体   繁体   English

typescript 交叉口类型 function

[英]typescript intersection types of function

I am using typescript and faced some problems.我正在使用 typescript 并遇到了一些问题。 The simplest demo would be:最简单的演示是:

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

I don't understand why type h is not never and param x in type i is 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?

Also, didn't understand why type e is 2 not never ?另外,不明白为什么 type e2而不是never

Note: non-primitive types are conventionally written in UpperCamelCase;注意:非原始类型通常用 UpperCamelCase 编写; this distinguishes them from primitive types and variable/property names.这将它们与原始类型和变量/属性名称区分开来。 I will use this convention in what follows.我将在下面使用这个约定。

There's a bunch of pieces to this question, and so there will be a bunch of pieces to its answer.这个问题有很多部分,所以它的答案也会有很多部分。


Let's tackle the easy ones first:让我们先解决简单的问题:

type G = 1 & 2 // never

The reduction to never of empty intersections like 1 & 2 was implemented in microsoft/TypeScript#31838 and released with TypeScript 3.6.microsoft/TypeScript#31838中实现了像1 & 2这样的空交叉点的减少,并随never 3.6 一起发布。 Before this, 1 & 2 was treated very much like never , in that you'd never be able to find a value that satisfies it.在此之前, 1 & 2的处理方式与never非常相似,因为您永远无法找到满足它的值。 There's really no conceptual difference between 1 & 2 and never , although it's possible compiler implementation details will cause one to be treated differently from the other. 1 & 2never之间实际上没有概念上的区别,尽管编译器实现细节可能会导致一个与另一个被区别对待。


Next one:下一个:

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

The x is never , but the reduction is deferred until you actually use it: xnever ,但减少会延迟到您实际使用它:

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

This deferral was implemented in microsoft/TypeScript#36696 and released with TypeScript 3.9.此延迟在microsoft/TypeScript#36696中实现,并与 TypeScript 3.9 一起发布。 Before this, x was eagerly reduced to never just like G above.在此之前, x被急切地简化为never像上面的G那样。


Now for some more complicated examples:现在来看一些更复杂的例子:

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

There are actually quite a few reasons why H is not never :实际上有很多原因H不是never

  • The TypeScript-specific reason is because an intersection of function types is considered the same as an overloaded function with multiple call signatures:特定于 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

    Notice how h is displayed as a function with two overloads;注意h如何显示为具有两个重载的 function; one which accepts a 1 parameter, and another which accepts a 2 parameter.一个接受1参数,另一个接受2参数。 It does not accept 3 , and it also does not accept 1 | 2它不接受3 ,也不接受1 | 2 1 | 2 even though from a pure type system perspective it probably should (see microsoft/TypeScript#14107 for a longstanding feature request to support this). 1 | 2即使从纯类型系统的角度来看它可能应该(参见microsoft/TypeScript#14107以获得支持这一点的长期功能请求)。

  • Even if TypeScript didn't interpret function-intersections as overloads, H should not be never .即使 TypeScript 没有将函数交集解释为重载, H也不应该是never Function types are contravariant in their parameter types (see my answer to this question for an explanation. You can also read about the contravariance of function parameters in the TS handbook description of the --strictFunctionTypes compiler flag ). Function 类型的参数类型是逆变的(有关解释,请参阅我对此问题的回答。您还可以--strictFunctionTypes编译器标志的 TS 手册描述中阅读 function 参数的逆变性)。 Contravariance turns things into their dual ;逆变将事物变成它们的对 If F<T> is contravariant in T , then F<T | U>如果F<T>T中是逆变的,则F<T | U> F<T | U> is equivalent to F<T> & T<U> , and F<T & U> is equivalent to F<T> | F<U> F<T | U>等价于F<T> & T<U> ,而F<T & U>等价于F<T> | F<U> F<T> | F<U> . F<T> | F<U> So a consistent type system, when asked for the parameter type of an intersection of functions would return the union of the function parameter types.因此,一个一致的类型系统,当要求函数交集的参数类型时,将返回function参数类型的并集。 And 1 | 21 | 2 1 | 2 is not never . 1 | 2不是never

  • Even if H were a completely uninhabited type, currently TypeScript only reduces intersections to never in particular situations, and an intersection of functions is not one of those.即使H一个完全无人居住的类型,目前 TypeScript 只是在特定情况下将交叉点减少到never ,功能交叉点不是其中之一。 If you look in the compiler source code file checker.ts it says "an intersection type is considered empty if it contains the type never , or more than one unit type or an object type and a nullable type ( null or undefined ), or a string -like type and a type known to be non- string -like, or a number -like type and a type known to be non- number -like, or a symbol -like type and a type known to be non- symbol -like, or a void -like type and a type known to be non- void -like, or a non-primitive type and a type known to be primitive."如果您查看编译器源代码文件checker.ts ,它会显示“如果交叉类型包含类型never或多个单元类型或 object 类型和可空类型( nullundefined ),则认为它为空,或者类string类型和已知非string类型,或类number类型和已知非类number类型,或类symbol类型和已知非symbol类型 - void void None of that says "two incompatible function types", so it is not reduced to never .没有一个说“两个不兼容的 function 类型”,所以它没有减少到never


Last one:最后一个:

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

Recall from earlier that an intersection of functions is considered to be an overloaded function.回想一下,函数的交集被认为是重载的 function。 It is a known design limitation of TypeScript that when using type inference on an overloaded function type, the compiler does not try to resolve the overload by figuring out which call signature matches the intended inference best. TypeScript 的一个已知设计限制是,在对重载的 function 类型使用类型推断时,编译器不会尝试通过确定哪个调用签名与预期的推断最匹配来解决过载问题。 It just uses the last call signature and ignores all the rest of them .它只使用最后一个调用签名并忽略其中的所有 rest In E , that means the compiler only sees (x: 2) => 0 when matching against (x: infer L) => 0 , and so L is inferred as 2 .E中,这意味着编译器仅在与(x: infer L) => 0匹配时看到(x: 2) => 0 > 0 ,因此L被推断为2 The "right" thing to do would probably be the union 1 | 2 “正确”的做法可能是联合1 | 2 1 | 2 , but this does not happen. 1 | 2 ,但这不会发生。 See microsoft/TypeScript#27027 for one instance of this limitation.有关此限制的一个实例,请参阅microsoft/TypeScript#27027


Playground link to code Playground 代码链接

in case如果

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

you assign 1 as a type for x also known as literal type.您将1分配为x的类型,也称为文字类型。 Literal type is next to never smallest set of values.文字类型几乎never最小的值集。 The difference between never and literal type 1 is that never is an empty set but 1 set which has exactly one value in it. never和字面量类型1之间的区别在于, never是一个空集,但1集合中只有一个值。 So that never !== 1所以never !== 1

here这里

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

type of parameter x is never参数x的类型never

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

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