簡體   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