TypeScript 3.3

改進了呼叫聯合型別的行為

在舊版本的 TypeScript 中,聯合型別的可呼叫型別只有在引數列表完全相同時才能被呼叫。

ts
type Fruit = "apple" | "orange";
type Color = "red" | "orange";
type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruit
type ColorConsumer = (color: Color) => string; // consumes and describes the colors
declare 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");

然而,在上面的示例中,FruitEaterColorConsumer 都應該能夠接收字串 "orange",並返回 numberstring

在 TypeScript 3.3 中,這不再是一個錯誤。

ts
type Fruit = "apple" | "orange";
type Color = "red" | "orange";
type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruit
type ColorConsumer = (color: Color) => string; // consumes and describes the colors
declare 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)在一起,以建立一個新的簽名。

在上面的例子中,引數 fruitcolor 被交集在一起,形成了一個型別為 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 設定下可能會存在一些問題。

ts
interface 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 中仍然具有更強的能力,且新增顯式型別註解可以解決這些問題。

ts
interface 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%你可以閱讀關於此更改的原始拉取請求以檢視具體資料,但我們相信大多數複合專案使用者將從這裡獲得顯著的效能收益。

TypeScript 文件是一個開源專案。請傳送 Pull Request 幫助我們改進這些頁面 ❤

此頁面的貢獻者
DRDaniel Rosenwasser (51)
OTOrta Therox (12)
NSNick Schonning (1)
JBJack Bates (1)
RARiley Avron (1)
3+

最後更新:2026 年 3 月 27 日