改進了呼叫聯合型別的行為
在舊版本的 TypeScript 中,聯合型別的可呼叫型別只有在引數列表完全相同時才能被呼叫。
tstype Fruit = "apple" | "orange";type Color = "red" | "orange";type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruittype ColorConsumer = (color: Color) => string; // consumes and describes the colorsdeclare let f: FruitEater | ColorConsumer;// Cannot invoke an expression whose type lacks a call signature.// Type 'FruitEater | ColorConsumer' has no compatible call signatures.ts(2349)f("orange");
然而,在上面的示例中,FruitEater 和 ColorConsumer 都應該能夠接收字串 "orange",並返回 number 或 string。
在 TypeScript 3.3 中,這不再是一個錯誤。
tstype Fruit = "apple" | "orange";type Color = "red" | "orange";type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruittype ColorConsumer = (color: Color) => string; // consumes and describes the colorsdeclare let f: FruitEater | ColorConsumer;f("orange"); // It works! Returns a 'number | string'.f("apple"); // error - Argument of type '"apple"' is not assignable to parameter of type '"orange"'.f("red"); // error - Argument of type '"red"' is not assignable to parameter of type '"orange"'.
在 TypeScript 3.3 中,這些簽名的引數會被交集(intersected)在一起,以建立一個新的簽名。
在上面的例子中,引數 fruit 和 color 被交集在一起,形成了一個型別為 Fruit & Color 的新引數。Fruit & Color 實際上等同於 ("apple" | "orange") & ("red" | "orange"),即 ("apple" & "red") | ("apple" & "orange") | ("orange" & "red") | ("orange" & "orange")。每一個不可能的交集都會簡化為 never,最後我們只剩下 "orange" & "orange",也就是 "orange"。
注意事項
這種新行為僅在聯合型別中最多隻有一個型別包含多個過載,且最多隻有一個型別具有泛型簽名時才會生效。這意味著 number[] | string[] 上的 map 等方法(它是泛型的)仍然無法呼叫。
另一方面,像 forEach 這樣的方法現在可以被呼叫了,但在 noImplicitAny 設定下可能會存在一些問題。
tsinterface Dog {kind: "dog";dogProp: any;}interface Cat {kind: "cat";catProp: any;}const catOrDogArray: Dog[] | Cat[] = [];catOrDogArray.forEach(animal => {// ~~~~~~ error!// Parameter 'animal' implicitly has an 'any' type.});
這在 TypeScript 3.3 中仍然具有更強的能力,且新增顯式型別註解可以解決這些問題。
tsinterface Dog {kind: "dog";dogProp: any;}interface Cat {kind: "cat";catProp: any;}const catOrDogArray: Dog[] | Cat[] = [];catOrDogArray.forEach((animal: Dog | Cat) => {if (animal.kind === "dog") {animal.dogProp;// ...} else if (animal.kind === "cat") {animal.catProp;// ...}});
在 --build --watch 中為複合專案提供增量檔案監視
TypeScript 3.0 引入了一項名為“複合專案”(composite projects)的構建結構化新功能。其部分目標是確保使用者可以將大型專案拆分為較小的部分,從而實現快速構建並保持專案結構,且不犧牲既有的 TypeScript 體驗。得益於複合專案,TypeScript 可以使用 --build 模式僅重新編譯相關的專案集和依賴項。你可以將其視為對跨專案構建的最佳化。
TypeScript 2.7 還透過一種新的增量“構建器”API 引入了 --watch 模式構建。同樣,這一理念在於該模式僅重新檢查和重新生成已更改的檔案,或其依賴關係可能影響型別檢查的檔案。你可以將其視為對專案內構建的最佳化。
在 3.3 版本之前,使用 --build --watch 構建複合專案實際上並未使用這種增量檔案監視基礎設施。在 --build --watch 模式下,專案中的任何更新都會強制對該專案進行完整構建,而不是確定該專案內哪些檔案受到了影響。
在 TypeScript 3.3 中,--build 模式的 --watch 標誌確實利用了增量檔案監視功能。這意味著在 --build --watch 下構建速度將顯著提升。在我們的測試中,此功能使原始的 --build --watch 構建時間減少了 50% 到 75%。你可以閱讀關於此更改的原始拉取請求以檢視具體資料,但我們相信大多數複合專案使用者將從這裡獲得顯著的效能收益。