<tbody id="5vw1z"></tbody>
<rp id="5vw1z"></rp>
  •  

    TypeScript 4.8 發布!重點新特性解讀

    TypeScript 4.8?于 8 月 25 日發布正式版,本次發布帶來了諸多新特性,我們一起來看幾個比較重要的改動:

    聯合類型、交叉類型、類型收窄的優化

    TypeScript 4.8?版本對?--strictNullChecks?帶來了一系列準確性和一致性的改進。主要體現在聯合類型、交叉類型以及類型收窄的工作方式上。

    例如,unknown?在本質上其實接近聯合類型?{}| null | undefined,因為它可以接受?null、undefined?和任何其他類型。TypeScript?現在可以識別這種情況,并允許從 unknown 類型賦值到?{}| null | undefined。

    function f(x: unknown, y: {} | null | undefined) {
        x = y; // ✅
        y = x; // ❌
    }

    另一個改動是?{}?與任何其他對象類型的交叉類型會簡化為這個對象類型:

    {} & object;  // object

    另外,{} & null?和?{} & undefined?的情況被棄用:

    {} & null;  // never
    {} & undefined;  // never

    所以內置?NonNullable?類型被簡化成了下面這樣:

    ❌ type NonNullable<T> = T extends null | undefined ? never : T;
    ✅ type NonNullable<T> = T & {};

    這些改進也增強了類型控制流分析的能力。例如,unknown?類型現在可以直接像?{} | null | undefined?一樣類型收窄:

    function narrowUnknownishUnion(x: {} | null | undefined) {
        if (x) {
            x;  // {}
        }
        else {
            x;  // {} | null | undefined
        }
    }
    
    function narrowUnknown(x: unknown) {
        if (x) {
            x;  // used to be 'unknown', now '{}'
        }
        else {
            x;  // unknown
        }
    }

    通用的值也會同樣的類型收窄。比如當我們檢查一個值是否為?null?或?undefined?時,就相當于讓他和?{}?進行交叉,也就是和?NonNullable?的類型是一樣的。所以我們現在可以定義出下面這樣的函數,而不需要實現任何類型斷言:

    function throwIfNullable<T>(value: T): NonNullable<T> {
        if (value === undefined || value === null) {
            throw Error("ConardLi:這里需要的是 Nullable 類型!");
        }
    
        return value;
    }

    優化對模板字符串中的 infer 類型推斷

    infer?可以在?extends?的條件語句中推斷待推斷的類型,比如下面這個簡單用法:

    type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

    在這個例子中,infer R 代表待推斷的返回值類型,如果 T 是一個函數,則返回函數的返回值,否則返回 any。

    我們再來看一個更高級的類型推斷的例子:

    type FirstIfString<T> =
        T extends [infer S, ...unknown[]]
            ? S extends string ? S : never
            : never;
    
     // string
    type A = FirstIfString<[string, number, number]>;
    
    // "hello"
    type B = FirstIfString<["hello", number, number]>;
    
    // "hello" | "world"
    type C = FirstIfString<["hello" | "world", boolean]>;
    
    // never
    type D = FirstIfString<[boolean, number, string]>;

    FirstIfString?是一個工具類型,意思是如果數據是一個數組,且第一個元素是一個字符串類型,就返回第一個元素,否則返回?never。

    這個寫法上稍為有點復雜了,因為要多判斷一次第一個元素是否為字符串類型,所以需要多寫一次三元運算符,所以?TypeScript 4.7?引入了更簡潔的語法?infer?和?extends?可以配合使用:

    type TryGetNumberIfFirst<T> =
        T extends [infer U extends number, ...unknown[]] ? U : never;

    TypeScript 4.8?對在模版字符串中使用?infer extends?的情況進行了優化,下面這種情況?infer?以前會被約束為一個原始類型,現在可以推斷出更精確的值:

    //  'number' -> '100'.
    type ConardLiNum = "100" extends `${infer U extends number}` ? U : never;
    
    // 'bigint' -> '100n'.
    type ConardLiBigInt = "100" extends `${infer U extends bigint}` ? U : never;
    
    // 'boolean' -> 'true'.
    type ConardLiBool = "true" extends `${infer U extends boolean}` ? U : never;

    對象類型比較錯誤提示

    在許多語言中,像?==?這樣的操作符在對象上會執行所謂的“值”相等。例如,在?Python?中,通過使用?==?檢查值是否等于空列表來檢查列表是否為空:

    if people_at_home == []:
        print("here's where I lie, broken inside. </3")
        adopt_animals()

    但是在?JavaScript?中不是這樣的,在對象之間的?==?和?===?檢查的其實是兩個對象的引用,這應該算作?JavaScript?早期的設計缺陷,所以?TypeScript?現在會對下面的代碼提示錯誤:

    if (peopleAtHome === []) {
    //  ~~~~~~~~~~~~~~~~~~~
    // This condition will always return 'false' since JavaScript compares objects by reference, not value.
        console.log("here's where I lie, broken inside. </3")
        adoptAnimals();
    }

    禁止在 JavaScript 文件中導入/導出類型

    TypeScript?以前允許?JavaScript?文件在?import?和?export?語句中導入和導出用類型聲明,但是不支持值的導入導出。這種行為是不正確的,因為在?ECMAScript?模塊下,不存在的值的命名導入和導出可能會導致運行時錯誤。當一個?JavaScript?文件在?——checkJs?下或通過?// @ts-check?注釋進行類型檢查時,TypeScript?現在會拋出錯誤。

    // @ts-check
    
    import { someValue, SomeType } from "some-module";
    
    /**
     * @type {SomeType}
     */
    export const myValue = someValue;
    
    /**
     * @typedef {string | number} MyType
     */
    
    // Will fail at runtime because 'MyType' is not a value.
    export { MyType as MyExportedType };

    要從另一個模塊引用類型,可以直接限定導入:

    ❌ import { someValue, SomeType } from "some-module";
    ✅ import { someValue } from "some-module";
      
      /**
    ❌  * @type {SomeType}
    ✅  * @type {import("some-module").SomeType}
       */
      export const myValue = someValue;

    要導出類型,只需在 JSDoc 中使用?/** @typedef */?注釋。@typedef?注釋已經自動從它們包含的模塊中導出類型。

      /**
       * @typedef {string | number} MyType
       */
    
    ✅ /**
    ✅  * @typedef {MyType} MyExportedType
    ✅  */
    ❌ export { MyType as MyExportedType };

    –build、–watch、–incremental 性能優化

    TypeScript 4.8?引入了幾個優化,可以提升?——watch?和?——incremental?以及?——build?的性能。例如,TypeScript?現在可以在?——watch?模式避免非用戶變更引發的額外變更、避免與其他可能監視?TypeScript?輸出的構建工具發生沖突、以增量復用等改進。

    經過實驗,在一個比較大的內部代碼庫中,許多簡單的常見操作減少了?10%-25%?的時間,而在無文件更改的情況下減少了大約?40% 的時間。

    「點點贊賞,手留余香」

    0

    給作者打賞,鼓勵TA抓緊創作!

    微信微信 支付寶支付寶

    還沒有人贊賞,快來當第一個贊賞的人吧!

    聲明:
    1. 本站所有文章教程及資源素材均來源于網絡與用戶分享或為本站原創,僅限用于學習和研究。
    2. 如果內容損害你的權益請聯系客服QQ:1642748312給予處理。
    碼云筆記 » TypeScript 4.8 發布!重點新特性解讀

    發表回復

    IT互聯網行業相關廣告投放 更專業 更精準

    立即查看 聯系我們
    亚洲 自拍 另类小说综合图区