99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

TypeScript 4.0 新特性介紹 - 元組類型與短路賦值解析

2025-03-25 14:50 更新

可變參數(shù)元組類型

想象一下在 JavaScript 中有一個(gè)叫 concat 的函數(shù),它接受兩個(gè)數(shù)組或元組類型并將它們連接起來創(chuàng)建一個(gè)新數(shù)組。

function concat(arr1, arr2) {
    return [...arr1, ...arr2];
}

還有一個(gè) tail 函數(shù),它接受一個(gè)數(shù)組或元組并返回除第一個(gè)元素外的所有元素。

function tail(arg) {
    const [_, ...result] = arg;
    return result;
}

在 TypeScript 中如何為這些函數(shù)添加類型呢?對(duì)于 concat,在舊版本的語言中我們只能嘗試寫一些重載。

function concat(arr1: [], arr2: []): [];
function concat<A>(arr1: [A], arr2: []): [A];
function concat<A, B>(arr1: [A, B], arr2: []): [A, B];
function concat<A, B, C>(arr1: [A, B, C], arr2: []): [A, B, C];
function concat<A, B, C, D>(arr1: [A, B, C, D], arr2: []): [A, B, C, D];
function concat<A, B, C, D, E>(arr1: [A, B, C, D, E], arr2: []): [A, B, C, D, E];
function concat<A, B, C, D, E, F>(arr1: [A, B, C, D, E, F], arr2: []): [A, B, C, D, E, F];

這僅僅是當(dāng)?shù)诙€(gè)數(shù)組為空時(shí)的七種重載。如果 arr2 有一個(gè)參數(shù),還需要添加更多重載。

TypeScript 4.0 引入了兩個(gè)基本更改以及推斷改進(jìn),使這些類型成為可能。

第一個(gè)更改是元組類型語法中的擴(kuò)展現(xiàn)在可以是泛型。這意味著我們可以在不知道實(shí)際類型的情況下,表示對(duì)元組和數(shù)組的高階操作。當(dāng)在這些元組類型中實(shí)例化泛型擴(kuò)展時(shí),它們可以生成其他數(shù)組和元組類型。

第二個(gè)更改是元組中的剩余元素可以出現(xiàn)在任何位置,而不僅僅是末尾!

通過結(jié)合這兩種行為,我們可以為 concat 編寫一個(gè)單一的、類型良好的簽名:

type Arr = readonly any[];
function concat<T extends Arr, U extends Arr>(arr1: T, arr2: U): [...T, ...U] {
    return [...arr1, ...arr2];
}

雖然這個(gè)簽名仍然有點(diǎn)長(zhǎng),但它只是一個(gè)不需要重復(fù)的簽名,并且在所有數(shù)組和元組上都能提供可預(yù)測(cè)的行為。


帶標(biāo)簽的元組元素

改進(jìn)元組類型和參數(shù)列表的體驗(yàn)很重要,因?yàn)樗梢宰屛覀冊(cè)诔R姷?JavaScript 習(xí)慣用法周圍獲得強(qiáng)類型驗(yàn)證。使用元組類型作為剩余參數(shù)就是一個(gè)關(guān)鍵點(diǎn)。

例如,以下使用元組類型作為剩余參數(shù)的函數(shù):

function foo(...args: [string, number]): void {
    // ...
}

對(duì)于任何調(diào)用 foo 的人來說,應(yīng)該與以下函數(shù)沒有區(qū)別:

function foo(arg0: string, arg1: number): void {
    // ...
}

在第一個(gè)例子中,我們沒有為第一個(gè)和第二個(gè)元素提供參數(shù)名。雖然這對(duì)類型檢查沒有影響,但缺少標(biāo)簽的元組位置可能使它們更難使用,更難傳達(dá)我們的意圖。

這就是為什么在 TypeScript 4.0 中,元組類型現(xiàn)在可以提供標(biāo)簽。

type Range = [start: number, end: number];

為了加深參數(shù)列表和元組類型之間的聯(lián)系,剩余元素和可選元素的語法鏡像了參數(shù)列表的語法。

type Foo = [first: number, second?: string, ...rest: any[]];

使用帶標(biāo)簽的元組時(shí),需要注意一些規(guī)則。例如,當(dāng)為元組元素添加標(biāo)簽時(shí),元組中的其他元素也必須有標(biāo)簽。

標(biāo)簽不會(huì)要求我們?cè)诮鈽?gòu)時(shí)以不同的方式命名變量。它們僅用于文檔和工具。


從構(gòu)造函數(shù)推斷類屬性

當(dāng)啟用 noImplicitAny 時(shí),TypeScript 4.0 現(xiàn)在可以使用控制流分析來確定類中屬性的類型。

class Square {
    area;
    sideLength;
    constructor(sideLength: number) {
        this.sideLength = sideLength;
        this.area = sideLength ** 2;
    }
}

在構(gòu)造函數(shù)并非所有路徑都分配給實(shí)例成員的情況下,屬性可能被視為 undefined

class Square {
    sideLength;
    constructor(sideLength: number) {
        if (Math.random()) {
            this.sideLength = sideLength;
        }
    }
    get area() {
        return this.sideLength ** 2;
    }
}

在你更了解情況時(shí)(例如,你有一個(gè) initialize 方法),仍然需要顯式的類型注解以及在 strictPropertyInitialization 下的確定性賦值斷言。

class Square {
    sideLength!: number;
    constructor(sideLength: number) {
        this.initialize(sideLength);
    }
    initialize(sideLength: number) {
        this.sideLength = sideLength;
    }
    get area() {
        return this.sideLength ** 2;
    }
}


短路賦值運(yùn)算符

JavaScript 和許多其他語言支持一組稱為復(fù)合賦值運(yùn)算符的運(yùn)算符。復(fù)合賦值運(yùn)算符對(duì)兩個(gè)參數(shù)應(yīng)用運(yùn)算符,然后將結(jié)果賦值給左側(cè)。你可能見過這些:

// 加法
a += b;
// 減法
a -= b;
// 乘法
a *= b;
// 除法
a /= b;
// 指數(shù)運(yùn)算
a **= b;
// 左移位
a <<= b;

直到最近,還有三個(gè)顯著的例外:邏輯與(&&)、邏輯或(||)和 nullish 合并(??)。

這就是為什么 TypeScript 4.0 支持 ECMAScript 的新功能,添加了三個(gè)新的賦值運(yùn)算符:&&=||=??=。

這些運(yùn)算符非常適合替代用戶可能編寫的代碼,例如:

a = a && b;
a = a || b;
a = a ?? b;

或者類似的 if 塊:

if (!a) {
    a = b;
}

還有一些我們見過的(或者我們自己寫過的)懶加載值的模式,只有在需要時(shí)才會(huì)初始化。

let values: string[];
(values ?? (values = [])).push("hello");
// 之后
(values ??= []).push("hello");

在罕見情況下,如果你使用帶有副作用的 getter 或 setter,需要注意這些運(yùn)算符只在必要時(shí)執(zhí)行賦值。從這個(gè)意義上說,不僅運(yùn)算符的右側(cè)被“短路”,賦值本身也被短路。

const obj = {
    get prop() {
        console.log("getter has run");
        return Math.random() < 0.5;
    },
    set prop(_val: boolean) {
        console.log("setter has run");
    }
};
function foo() {
    console.log("right side evaluated");
    return true;
}
console.log("This one always runs the setter");
obj.prop = obj.prop || foo();
console.log("This one *sometimes* runs the setter");
obj.prop ||= foo();


在 catch 子句綁定中使用 unknown 類型

從 TypeScript 誕生之初,catch 子句變量一直被類型化為 any。這意味著 TypeScript 允許你對(duì)它們做任何事情。

try {
    // 做一些工作
} catch (x) {
    // x 的類型是 'any' - 玩得開心!
    console.log(x.message);
    console.log(x.toUpperCase());
    x++;
    x.yadda.yadda.yadda();
}

如果我們?cè)噲D在錯(cuò)誤處理代碼中防止更多錯(cuò)誤發(fā)生,這可能會(huì)帶來一些不良行為!因?yàn)檫@些變量默認(rèn)具有 any 類型,它們?nèi)狈θ魏晤愋桶踩?,可能?huì)在無效操作上出錯(cuò)。

這就是為什么 TypeScript 4.0 現(xiàn)在允許你將 catch 子句變量的類型指定為 unknownunknownany 更安全,因?yàn)樗嵝盐覀冃枰诓僮髦抵斑M(jìn)行某種類型檢查。

try {
    // ...
} catch (e: unknown) {
    // 不能訪問 unknown 類型的值
    console.log(e.toUpperCase());
    if (typeof e === "string") {
        // 我們已經(jīng)將 'e' 窄化為 'string' 類型
        console.log(e.toUpperCase());
    }
}

雖然 catch 變量的類型不會(huì)默認(rèn)改變,但我們可能會(huì)考慮在未來添加一個(gè)新的 strict 模式標(biāo)志,以便用戶可以選擇這種行為。同時(shí),應(yīng)該可以編寫一個(gè) lint 規(guī)則來強(qiáng)制 catch 變量具有顯式的 : any: unknown 注解。


自定義 JSX 工廠

在使用 JSX 時(shí),片段是一種允許我們返回多個(gè)子元素的 JSX 元素類型。當(dāng)我們首次在 TypeScript 中實(shí)現(xiàn)片段時(shí),我們對(duì)其他庫(kù)如何利用它們沒有很好的想法。如今,大多數(shù)鼓勵(lì)使用 JSX 并支持片段的庫(kù)都有類似的 API 形狀。

在 TypeScript 4.0 中,用戶可以通過新的 jsxFragmentFactory 選項(xiàng)自定義片段工廠。

例如,以下 tsconfig.json 文件告訴 TypeScript 以與 React 兼容的方式轉(zhuǎn)換 JSX,但將每個(gè)工廠調(diào)用切換為 h 而不是 React.createElement,并使用 Fragment 而不是 React.Fragment。

{
    "": {
        "": "esnext",
        "": "commonjs",
        "": "react",
        "": "h",
        "": "Fragment"
    }
}

在需要在每個(gè)文件中使用不同的 JSX 工廠的情況下,可以利用新的 /** @jsxFrag */ 注釋 pragma。例如,以下代碼:

// 注意:這些注釋 pragma 需要以 JSDoc 風(fēng)格的多行語法編寫才能生效
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from "preact";
export const Header = (
    <>
        <h1>Welcome</h1>
    </>
);

將被轉(zhuǎn)換為以下輸出 JavaScript:

import React from 'react';
export const Header = React.createElement(
    React.Fragment,
    null,
    React.createElement("h1", null, "Welcome")
);


構(gòu)建模式下使用 --noEmitOnError 的速度提升

以前,在 incremental 模式下使用 noEmitOnError 標(biāo)志編譯一個(gè)有錯(cuò)誤的程序會(huì)非常慢。這是因?yàn)樯洗尉幾g的信息不會(huì)基于 noEmitOnError 標(biāo)志緩存在 .tsbuildinfo 文件中。

TypeScript 4.0 改變了這一點(diǎn),在這些場(chǎng)景中提供了巨大的速度提升,并且反過來改進(jìn)了 --build 模式(隱含 incrementalnoEmitOnError)。


使用 --incremental 和 --noEmit

TypeScript 4.0 允許我們?cè)谑褂?noEmit 標(biāo)志的同時(shí)仍然利用增量編譯。這以前是不允許的,因?yàn)?incremental 需要生成 .tsbuildinfo 文件;然而,啟用更快增量構(gòu)建的用例對(duì)于所有用戶來說都足夠重要。


編輯器改進(jìn)

TypeScript 編譯器不僅為大多數(shù)主要編輯器中的 TypeScript 本身提供編輯體驗(yàn),還為 Visual Studio 系列編輯器中的 JavaScript 體驗(yàn)提供支持。因此,我們的很多工作都集中在改進(jìn)編輯器場(chǎng)景上——這是你作為開發(fā)人員花費(fèi)大部分時(shí)間的地方。

在編輯器中使用新的 TypeScript/JavaScript 功能會(huì)因編輯器而異,但

  • Visual Studio Code 支持選擇不同版本的 TypeScript。或者,可以使用 JavaScript/TypeScript 夜ly版本擴(kuò)展來保持最新(這通常非常穩(wěn)定)。
  • Visual Studio 2017/2019 有 SDK 安裝程序和 MSBuild 安裝。
  • Sublime Text 3 支持選擇不同版本的 TypeScript

你可以查看支持 TypeScript 的編輯器列表,了解更多你最喜歡的編輯器是否支持使用新版本。


轉(zhuǎn)換為可選鏈?zhǔn)秸{(diào)用

可選鏈?zhǔn)秸{(diào)用是一個(gè)最近受到很多喜愛的功能。這就是為什么 TypeScript 4.0 帶來了一個(gè)新的重構(gòu),將常見的模式轉(zhuǎn)換為利用可選鏈?zhǔn)秸{(diào)用和 nullish 合并!


@deprecated 支持

TypeScript 的編輯支持現(xiàn)在可以識(shí)別聲明是否被 /** @deprecated */ JSDoc 注釋標(biāo)記。這些信息會(huì)在完成功能列表中顯示,并作為編輯器可以特別處理的建議診斷。在像 VS Code 這樣的編輯器中,已棄用的值通常會(huì)以刪除線樣式顯示。


啟動(dòng)時(shí)的部分語義模式

我們聽到了很多用戶在大型項(xiàng)目中啟動(dòng)時(shí)間過長(zhǎng)的反饋。罪魁禍?zhǔn)淄ǔJ欠Q為程序構(gòu)建的過程。這是從初始根文件集開始,解析它們,查找它們的依賴項(xiàng),解析這些依賴項(xiàng),查找這些依賴項(xiàng)的依賴項(xiàng),依此類推的過程。項(xiàng)目越大,你等待基本編輯操作(如轉(zhuǎn)到定義或快速信息)的時(shí)間就越長(zhǎng)。

這就是為什么我們一直在為編輯器開發(fā)一種新的模式,在完整語言服務(wù)體驗(yàn)加載之前提供部分體驗(yàn)。核心思想是編輯器可以運(yùn)行一個(gè)輕量級(jí)的部分服務(wù)器,只查看編輯器當(dāng)前打開的文件。

很難確切地說你會(huì)看到什么樣的改進(jìn),但根據(jù)經(jīng)驗(yàn),以前在 Visual Studio Code 代碼庫(kù)上,TypeScript 完全響應(yīng)需要 20 秒到一分鐘。相比之下,我們的新部分語義模式似乎將延遲縮短到只需幾秒鐘。

目前,只有 Visual Studio Code 支持這種模式,并且在 Visual Studio Code Insiders 中有一些用戶體驗(yàn)改進(jìn)即將推出。我們認(rèn)識(shí)到這種體驗(yàn)在用戶體驗(yàn)和功能上可能仍有改進(jìn)空間,我們有一系列改進(jìn)想法。我們希望獲得更多關(guān)于你認(rèn)為可能有用的反饋。


更智能的自動(dòng)導(dǎo)入

自動(dòng)導(dǎo)入是一個(gè)讓編碼變得更加容易的出色功能,但每當(dāng)自動(dòng)導(dǎo)入似乎無法正常工作時(shí),都會(huì)讓用戶感到困惑。我們從用戶那里聽到的一個(gè)具體問題是,自動(dòng)導(dǎo)入在 TypeScript 編寫的依賴項(xiàng)上無法正常工作,直到他們?cè)陧?xiàng)目中的其他地方至少顯式導(dǎo)入了一次。

為什么自動(dòng)導(dǎo)入對(duì) @types 包有效,但對(duì)自帶類型的包無效?事實(shí)證明,自動(dòng)導(dǎo)入只對(duì)你的項(xiàng)目已經(jīng)包含的包有效。因?yàn)?TypeScript 有一些奇怪的默認(rèn)行為,會(huì)自動(dòng)將 node_modules/@types 中的包添加到你的項(xiàng)目中,所以這些包會(huì)被自動(dòng)導(dǎo)入。另一方面,其他包被排除在外,因?yàn)楸闅v所有 node_modules 包可能會(huì)非常昂貴。

所有這些都導(dǎo)致了一個(gè)很糟糕的初始體驗(yàn),當(dāng)你試圖自動(dòng)導(dǎo)入一個(gè)剛剛安裝但尚未使用過的包時(shí)。

TypeScript 4.0 現(xiàn)在在編輯器場(chǎng)景中做了一些額外的工作,以包含你在 package.jsondependencies(和 peerDependencies)字段中列出的包。這些包中的信息僅用于改進(jìn)自動(dòng)導(dǎo)入,不會(huì)改變類型檢查等其他任何內(nèi)容。這允許我們?yōu)樗袔в蓄愋偷囊蕾図?xiàng)提供自動(dòng)導(dǎo)入,而無需承擔(dān)完整 node_modules 搜索的成本。

在罕見情況下,當(dāng)你的 package.json 列出了超過十個(gè)尚未導(dǎo)入的帶類型依賴項(xiàng)時(shí),此功能會(huì)自動(dòng)禁用,以防止項(xiàng)目加載緩慢。要強(qiáng)制啟用此功能或完全禁用它,你應(yīng)該能夠配置你的編輯器。對(duì)于 Visual Studio Code,這是“包含包 JSON 自動(dòng)導(dǎo)入”(或 typescript.preferences.includePackageJsonAutoImports)設(shè)置。


我們的新網(wǎng)站

TypeScript 網(wǎng)站最近已經(jīng)從頭重寫并推出!

我們已經(jīng)寫了一些關(guān)于新網(wǎng)站的內(nèi)容,所以你可以在那里了解更多;但值得一提的是,我們?nèi)匀幌M牭侥愕南敕ǎ∪绻阌腥魏螁栴}、評(píng)論或建議,可以在網(wǎng)站的問題跟蹤器上提交。


破壞性更改

lib.d.ts 更改

我們的 lib.d.ts 聲明已更改——最具體來說,DOM 的類型已更改。最顯著的更改可能是移除了 document.origin,它僅在舊版本的 IE 和 Safari 中有效。MDN 建議遷移到 self.origin


屬性覆蓋訪問器(反之亦然)是一個(gè)錯(cuò)誤

以前,只有在使用 useDefineForClassFields 時(shí),屬性覆蓋訪問器或訪問器覆蓋屬性才會(huì)報(bào)錯(cuò);然而,TypeScript 現(xiàn)在在派生類中聲明會(huì)覆蓋基類中的 getter 或 setter 的屬性時(shí)始終會(huì)報(bào)錯(cuò)。

class Base {
    get foo() {
        return 100;
    }
    set foo(value) {
        // ...
    }
}
class Derived extends Base {
    foo = 10;
}
class Base {
    prop = 10;
}
class Derived extends Base {
    get prop() {
        return 100;
    }
}


delete 的操作數(shù)必須是可選的

strictNullChecks 中使用 delete 運(yùn)算符時(shí),操作數(shù)現(xiàn)在必須是 any、unknownnever 或是可選的(即類型中包含 undefined)。否則,使用 delete 運(yùn)算符會(huì)報(bào)錯(cuò)。

interface Thing {
    prop: string;
}
function f(x: Thing) {
    delete x.prop;
}


使用 TypeScript 的節(jié)點(diǎn)工廠已棄用

如今,TypeScript 提供了一組用于生成 AST 節(jié)點(diǎn)的“工廠”函數(shù);然而,TypeScript 4.0 提供了一個(gè)新的節(jié)點(diǎn)工廠 API。因此,對(duì)于 TypeScript 4.0,我們決定棄用這些舊函數(shù),以支持新的函數(shù)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)