動態匯入表示式 (Dynamic Import Expressions)
動態 import 表示式是一項新功能,屬於 ECMAScript 的一部分,允許使用者在程式的任何位置非同步請求模組。
這意味著你可以按條件和延遲匯入其他模組和庫。例如,下面是一個 async 函式,它僅在需要時才匯入實用工具庫:
tsasync function getZipFile(name: string, files: File[]): Promise<File> {const zipUtil = await import("./utils/create-zip-file");const zipContents = await zipUtil.getContentAsBlob(files);return new File(zipContents, name);}
許多打包工具支援根據這些 import 表示式自動拆分輸出包,因此請考慮將此新功能與 esnext 模組目標一起使用。
字串列舉 (String Enums)
TypeScript 2.4 現在允許列舉成員包含字串初始化表示式。
tsenum Colors {Red = "RED",Green = "GREEN",Blue = "BLUE"}
需要注意的是,字串初始化的列舉無法進行反向對映以獲取原始列舉成員名稱。換句話說,你不能透過 Colors["RED"] 來獲取字串 "Red"。
改進了泛型推斷
TypeScript 2.4 針對泛型推斷的方式引入了一些極好的改進。
將返回型別作為推斷目標
首先,TypeScript 現在可以針對呼叫的返回型別進行推斷。這可以改善你的開發體驗並捕獲錯誤。以下程式碼現在可以正常工作:
tsfunction arrayMap<T, U>(f: (x: T) => U): (a: T[]) => U[] {return a => a.map(f);}const lengths: (a: string[]) => number[] = arrayMap(s => s.length);
作為這一變動可能導致的新錯誤示例:
tslet x: Promise<string> = new Promise(resolve => {resolve(10);// ~~ Error!});
基於上下文型別的型別引數推斷
在 TypeScript 2.4 之前,在以下示例中:
tslet f: <T>(x: T) => T = y => y;
y 的型別將為 any。這意味著程式可以透過型別檢查,但你實際上可以對 y 進行任何操作,例如:
tslet f: <T>(x: T) => T = y => y() + y.foo.bar;
最後一個示例實際上並不是型別安全的。
在 TypeScript 2.4 中,右側的函式隱式獲得了型別引數,並且 y 被推斷為該型別引數的型別。
如果你以型別引數的約束不支援的方式使用 y,你將正確地獲得一個錯誤。在這種情況下,T 的約束(隱式地)為 {},因此最後一個示例將適當地報錯。
泛型函式更嚴格的檢查
TypeScript 現在嘗試在比較兩個單簽名型別時統一型別引數。因此,你在關聯兩個泛型簽名時會得到更嚴格的檢查,並可能捕獲一些 Bug。
tstype A = <T, U>(x: T, y: U) => [T, U];type B = <S>(x: S, y: S) => [S, S];function f(a: A, b: B) {a = b; // Errorb = a; // Ok}
回撥引數的嚴格逆變 (Strict Contravariance)
TypeScript 一直以雙向協變的方式比較引數。這有多種原因,但總的來說,在我們看到它對 Promise 和 Observable 產生的一些負面影響之前,這並不是使用者的主要困擾。
TypeScript 2.4 在關聯兩個回撥型別時加強了這一點。例如:
tsinterface Mappable<T> {map<U>(f: (x: T) => U): Mappable<U>;}declare let a: Mappable<number>;declare let b: Mappable<string | number>;a = b;b = a;
在 TypeScript 2.4 之前,這個示例會成功。當關聯 map 的型別時,TypeScript 會雙向關聯它們的引數(即 f 的型別)。當關聯每個 f 時,TypeScript 也會雙向關聯那些引數的型別。
在 TS 2.4 中關聯 map 的型別時,語言將檢查每個引數是否為回撥型別;如果是,它將確保這些引數相對於當前關係以逆變的方式進行檢查。
換句話說,TypeScript 現在可以捕獲上述 Bug,這對於某些使用者來說可能是破壞性變更,但總體上是有幫助的。
弱型別檢測 (Weak Type Detection)
TypeScript 2.4 引入了“弱型別”的概念。任何只包含可選屬性的型別都被視為弱型別。例如,這個 Options 型別就是一個弱型別:
tsinterface Options {data?: string;timeout?: number;maxRetries?: number;}
在 TypeScript 2.4 中,當沒有屬性重疊時,將任何內容分配給弱型別現在會報錯。例如:
tsfunction sendMessage(options: Options) {// ...}const opts = {payload: "hello world!",retryOnFail: true};// Error!sendMessage(opts);// No overlap between the type of 'opts' and 'Options' itself.// Maybe we meant to use 'data'/'maxRetries' instead of 'payload'/'retryOnFail'.
你可以將此視為 TypeScript 在“加強”這些型別的弱保證,以捕獲原本會悄無聲息發生的 Bug。
由於這是一個破壞性變更,你可能需要了解解決方法,這些方法與嚴格物件字面量檢查的解決方法相同:
- 如果屬性確實存在,請宣告這些屬性。
- 向弱型別新增索引簽名(即
[propName: string]: {})。 - 使用型別斷言(即
opts as Options)。