TypeScript 4.0正式發佈!如今是開始使用它的最佳時機

做者 | Daniel Rosenwasser
譯者 | 王強
策劃 | 李俊辰
今天,微軟宣佈 TypeScript 4.0 正式版上線了!這一新版本深刻改進了表現力、生產力和可伸縮性,是 TypeScript 語言的新一代版本。

若是你還不熟悉 TypeScript,這裏簡單介紹一下:它是一種在 JavaScript 之上經過添加靜態類型語法來構建的語言。它的基本理念是,記下值的類型以及它們的使用位置後,可使用 TypeScript 對代碼進行類型檢查,並在運行代碼以前(甚至在保存文件以前)告訴你代碼錯誤的相關信息。而後,你可使用 TypeScript 編譯器從代碼中剝離類型,併爲你提供可在任何地方運行的簡潔易讀的 JavaScript 代碼。除了類型檢查以外,TypeScript 還使用靜態類型來支持強大的編輯器工具,例如自動完成、代碼導航、重構等。實際上,若是你在 Visual Studio Code 或 Visual Studio 這樣的編輯器中使用過 JavaScript,那麼你已經用上了類型和 TypeScript 帶來的體驗。能夠在咱們的網站上了解更多相關信息。前端

https://www.typescriptlang.org/node

TypeScript 4.0 沒有引入特別重大的更改。實際上,若是你剛剛開始接觸這種語言,那麼如今是開始使用它的最佳時機。它的社區已經成熟完善,並在不斷髮展,擁有可運行的代碼和很棒的新資源可供學習。還有一件事情:儘管咱們爲 4.0 引入了那麼多好東西,但你實際上只須要了解 TypeScript 的基礎知識就能夠開始生產應用了!react

若是你已經在項目中使用 TypeScript,則能夠經過 NuGet 獲取它,也能夠經過如下命令使用 npm 獲取:
npm install -D typescript

你還能夠經過如下方式得到編輯器支持:
git

  • 下載 Visual Studio 2019/2017:github

    • https://marketplace.visualstudio.com/items?itemName=TypeScriptTeam.TypeScript-40web

  • 安裝 Visual Studio Code 的內部版本,或按照如下說明使用較新版本的 TypeScript。typescript

    • https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-newer-typescript-versionsnpm

4.0 之旅 

TypeScript 是當今許多人的 JavaScript 技術棧的核心部分。在 npm 上,TypeScript 在 7 月首次實現了超過 5000 萬的月下載量!儘管咱們知道它總有增加和改進的餘地,但很明顯,大多數使用 TypeScript 編碼的開發人員確實很喜歡它。StackOverflow 的最新開發人員調查將 TypeScript 列爲第二受歡迎的語言。在最新的 JS 現狀調查中,使用 TypeScript 的開發人員中有大約 89% 表示會再次使用它。編程

值得一提的是咱們走到今天所走過的旅程。在以前的兩個主要版本中,咱們回顧了多年來閃耀的一些亮點。對於 TypeScript 4.0,咱們將保持這種傳統。json

從 3.0 版本向前看,能夠看到許多使人眼花繚亂的更改,可是 TypeScript 3.0 自己就產生了很大的衝擊。統一元組類型和參數列表是當時的一大亮點,可在函數上啓用大量已有的 JavaScript 模式。這個發行版還提供了項目參考,以幫助擴展、組織和共享代碼庫。3.0 版的一個產生重大影響的小更改是對 any 引入了類型安全的替代方法,稱爲 unknown。

TypeScript 3.1 擴展了映射類型的功能以處理元組和數組類型,並極大簡化了將屬性附加到函數的過程,而無需使用 TypeScript 專屬的運行時功能(已停用)。

TypeScript 3.2 容許對象在泛型類型上傳播,並經過嚴格類型化 bind、call 和 apply,利用 3.0 的功能更好地建模函數的元編程。TypeScript 3.3 更多關注穩定性,但也改進了聯合類型方法,並在 --build 模式下添加了文件增量式構建。

在 3.4 版本中,咱們進一步支持函數式模式,更好地支持不可變數據結構,並改進了對高階泛型函數的推斷。這個發行版的一大改進是引入了 --incremental 標誌,該方法避免了在每次 TypeScript 運行時徹底重建,從而加快了編譯和類型檢查的速度。

在 TypeScript 3.5 和 3.6 中增強了一些類型系統規則,還帶來了更智能的兼容性檢查規則。

TypeScript 3.7 是一個很是值得關注的版本,由於它很好地結合了許多新的類型系統特性與 ECMAScript 特性。在類型系統方面,咱們加入了遞歸類型別名引用和對斷言樣式函數的支持,這二者都是獨特的類型系統特性。從 JavaScript 方面來看,該版本帶來了可選鏈和空值合併功能,這是 TypeScript 和 JavaScript 用戶最期待的兩項功能。

最近,3.8 和 3.9 帶來了僅類型的導入 / 導出,以及許多 ECMAScript 特性,例如私有字段、模塊中的頂級 await 和新的 export* 語法。這些版本還帶來了性能和可伸縮性優化。

咱們尚未提到關於語言服務、基礎架構、網站和其餘核心項目中的那些工做,這些工做對於 TypeScript 的體驗很是關鍵。核心團隊的項目以外,咱們在生態系統中還有很是出色的貢獻者社區,他們推進了體驗的不斷改進,並經過 DefinitelyTyped 甚至 TypeScript 自己提供了幫助。在 2012 年剛開始時,DefinitelyTyped 僅有 80 個拉取請求。在 2019 年,它有超過 8300 個拉取請求,很是震撼人心。這些貢獻是 TypeScript 體驗的基礎,這樣一個繁忙而熱情的社區在不斷改善咱們的生態系統,並推進咱們不斷改進,咱們對此表示感謝。

可變元組類型
考慮 JavaScript 中稱爲 concat 的函數,該函數接收兩個數組或元組類型,並將它們鏈接在一塊兒以建立一個新數組。
function concat(arr1, arr2) {
    return [...arr1, ...arr2];
}
考慮 tail,它接收一個數組或元組,並返回除第一個元素外的全部元素。
function tail(arg) {
    const [_, ...result] = arg;
    return result
}
咱們如何在 TypeScript 中爲它們類型化?對於 concat,咱們在較舊版本的 TS 中惟一能夠作的就是嘗試編寫一些重載。
function concat<>(arr1: [], arr2: []): [A];
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];)
第二個數組始終爲空時會冒出來七個重載。當 arr2 有一個參數時咱們再加一些看看。
function concat<A2>(arr1: [], arr2: [A2]): [A2];
function concat<A1, A2>(arr1: [A1], arr2: [A2]): [A1, A2];
function concat<A1, B1, A2>(arr1: [A1, B1], arr2: [A2]): [A1, B1, A2];
function concat<A1, B1, C1, A2>(arr1: [A1, B1, C1], arr2: [A2]): [A1, B1, C1, A2];
function concat<A1, B1, C1, D1, A2>(arr1: [A1, B1, C1, D1], arr2: [A2]): [A1, B1, C1, D1, A2];
function concat<A1, B1, C1, D1, E1, A2>(arr1: [A1, B1, C1, D1, E1], arr2: [A2]): [A1, B1, C1, D1, E1, A2];
function concat<A1, B1, C1, D1, E1, F1, A2>(arr1: [A1, B1, C1, D1, E1, F1], arr2: [A2]): [A1, B1, C1, D1, E1, F1, A2];
很明顯這變得愈來愈離譜了。不幸的是,在類型化 tail 之類的函數時,你也會遇到一樣的問題。下面是另外一種狀況,咱們稱之爲「被一千個重載搞垮」,它甚至什麼問題都解決不了。它只爲咱們想寫的重載提供正確的類型(無論重載有多少)。若是咱們想作一個通行模式,就須要下面這種重載:
function concat<T, U>(arr1: T[], arr2, U[]): Array<T | U>;

但在使用元組時,這個簽名不會包含輸入長度或元素順序的任何信息。TypeScript 4.0 帶來了兩個基礎更改,並在推斷方面進行了改進,從而能夠類型化這些內容。

第一個更改是元組類型語法中的 spread 如今能夠泛型。這意味着即便咱們不知道要操做的實際類型,也能夠表示對元組和數組的高階操做。在這些元組類型中實例化泛型 spread(或用真實類型替換)時,它們能夠產生其餘數組和元組類型集。

例如,咱們能夠類型化 tail 那樣的函數,而不會出現「被一千個重載搞垮」的問題。
function tail<T extends any[]>(arr: readonly [any, ...T]) {
    const [_ignored, ...rest] = arr;
    return rest;
}
const myTuple = [1, 2, 3, 4] as const;
const myArray = ["hello", "world"];
// type [2, 3, 4]
const r1 = tail(myTuple);
// type [2, 3, ...string[]]
const r2 = tail([...myTuple, ...myArray] as const);
第二個更改是,rest 元素能夠出如今元組中的任何位置,而不只僅是在結尾!
type Strings = [string, string];
type Numbers = [number, number];
// [string, string, number, number]
type StrStrNumNum = [...Strings, ...Numbers];
之前,TypeScript 會發出以下錯誤。
A rest element must be last in a tuple type.

可是如今這種限制取消了。

當咱們在沒有已知長度的類型中 spread 時,結果類型也將變得不受限制,而且後面的全部元素都會變爲結果的 rest 元素類型。
type Strings = [string, string];
type Numbers = number[]
// [string, string, ...Array<number | boolean>]
type Unbounded = [...Strings, ...Numbers, boolean];
將這兩種行爲結合在一塊兒,咱們能夠爲 concat 編寫一個類型良好的簽名:
type Arr = readonly any[];
function concat<T extends Arr, U extends Arr>(arr1: T, arr2: U): [...T, ...U] {
    return [...arr1, ...arr2];
}

儘管一個簽名仍然有些冗長,但它畢竟只有一個,只需寫一次,而且在全部數組和元組上都具備可預測的行爲。

這個功能很棒,在其餘更復雜的場景中更有用。例如,考慮一個函數來部分應用參數,名爲 partialCall。partialCall 接收一個函數(這裏就叫 f)以及該函數指望的幾個初始參數。而後,它返回一個新函數,接收它須要的其餘全部參數,收到後調用 f。
function partialCall(f, ...headArgs) {
    return (...tailArgs) => f(...headArgs, ...tailArgs)
}
TypeScript 4.0 改進了 rest 參數和 rest 元組元素的推斷過程,所以咱們能夠類型化它並使其「正常工做」。
type Arr = readonly unknown[];
function partialCall<T extends Arr, U extends Arr, R>(f: (...args: [...T, ...U]) => R, ...headArgs: T) {
    return (...b: U) => f(...headArgs, ...b)
}
在這種狀況下,partialCall 會知道其最初可使用和不能使用哪些參數,並返回一個能夠正確接收和拒絕剩餘內容的函數。
const foo = (x: string, y: number, z: boolean) => {}
// This doesn't work because we're feeding in the wrong type for 'x'.
const f1 = partialCall(foo, 100);
// ~~~
// error! Argument of type 'number' is not assignable to parameter of type 'string'.

// This doesn't work because we're passing in too many arguments.
const f2 = partialCall(foo, "hello", 100, true, "oops")
// ~~~~~~
// error! Expected 4 arguments, but got 5.

// This works! It has the type '(y: number, z: boolean) => void'
const f3 = partialCall(foo, "hello");
// What can we do with f3 now?
f3(123, true); // works!
f3();
// error! Expected 2 arguments, but got 0.
f3(123, "hello");
// ~~~~~~~
// error! Argument of type '"hello"' is not assignable to parameter of type 'boolean'.

可變元組類型創造了許多新模式,尤爲是在函數組合方面。咱們但願利用它來改善對 JavaScript 內置的 bind 方法的類型檢查。此外還有其餘一些推斷改進和模式,想了解更多信息,能夠查看可變元組的拉取請求。

https://github.com/microsoft/TypeScript/pull/39094

標記的元組元素

改善元組類型和參數列表的體驗很重要,由於它使咱們可以圍繞常見的 JavaScript 習慣用法進行強類型驗證——實際上只是對參數列表進行切片和切塊,並將它們傳遞給其餘函數。對 rest 參數使用元組類型是其中的關鍵。

例如,如下函數使用元組類型做爲 rest 參數:
function foo(...args: [string, number]): void {
    // ...
}
應該與如下函數沒有區別。
function foo(arg0: string, arg1: number): void {
    // ...
}
對於 foo 的任何調用者。
foo("hello", 42); // works
foo("hello", 42, true); // error
foo("hello"); // error
不過可讀性就有區別了。在第一個示例中,咱們沒有第一個和第二個元素的參數名稱。儘管這些對類型檢查沒有影響,但元組位置上缺乏標記會難以傳達咱們的意圖。所以,在 TypeScript 4.0 中,元組類型如今能夠提供標記。
type Range = [start: number, end: number];
爲了進一步增強參數列表和元組類型之間的聯繫,咱們讓 rest 元素和可選元素的語法與參數列表的語法一致。
type Foo = [first: number, second?: string, ...rest: any[]];
標記元組使用時有些規則,其中一條是:在標記一個元組元素時,還必須標記元組中的全部其餘元素。
type Bar = [first: string, number];
// ~~~~~~
// error! Tuple members must all have names or all not have names.
值得注意的是,在解構時標記不須要咱們用不一樣的名稱命名變量。它們純粹是爲文檔和工具鏈服務的。
function foo(x: [first: string, second: number]) {
    // ...
    // note: we didn't need to name these 'first' and 'second'
    let [a, b] = x;
    // ...
}

總的來講,當利用圍繞元組和參數列表的模式,並以類型安全的方式實現重載時,帶標記的元組很是方便好用。實際上,TypeScript 的編輯器支持會在可能的狀況下將它們顯示爲重載。

瞭解更多信息,請查看帶標記的元組元素的拉取請求。

https://github.com/microsoft/TypeScript/pull/38234

構造器的類屬性推斷
當啓用 noImplicitAny 時,TypeScript 4.0 如今可使用控制流分析來肯定類中屬性的類型。
class Square {
    // Previously: implicit any!
    // Now: inferred to `number`!
    area;
    sideLength;
    constructor(sideLength: number) {
        this.sideLength = sideLength;
        this.area = sideLength ** 2;
    }
}
若是構造器的路徑並不是都分配給一個實例成員,則該屬性可能被認爲是 undefined 的。
class Square {
    sideLength;
    constructor(sideLength: number) {
        if (Math.random()) {
            this.sideLength = sideLength;
        }
    }
    get area() {
        return this.sideLength ** 2;
        // ~~~~~~~~~~~~~~~
        // error! Object is possibly 'undefined'.
    }
}
若是你更瞭解某些狀況(例如,你擁有某種 initialize 方法),則當你處於 strictPropertyInitialization 中時,須要使用顯式類型註釋以及明確的賦值斷言(!)。
class Square {
    // definite assignment assertion
    // v
    sideLength!: number;
    // ^^^^^^^^
    // type annotation
    constructor(sideLength: number) {
        this.initialize(sideLength)
    }
    initialize(sideLength: number) {
        this.sideLength = sideLength;
    }
    get area() {
        return this.sideLength ** 2;
    }
}

更多信息請見拉取請求。

https://github.com/microsoft/TypeScript/pull/379200

短路賦值運算符
JavaScript 和許多語言都支持一組稱爲"複合賦值運算符"的運算符。複合賦值運算符將一個運算符應用於兩個參數,而後將結果賦給左側。你可能之前看過這些:
// Addition
// a = a + b
a += b;
// Subtraction
// a = a - b
a -= b;
// Multiplication
// a = a * b
a *= b;
// Division
// a = a / b
a /= b;
// Exponentiation
// a = a ** b
a **= b;
// Left Bit Shift
// a = a << b
a <<= b;

JavaScript 中有不少運算符都有對應的賦值運算符!可是有三個值得注意的例外:邏輯和(&&),邏輯或(||)和空值合併(??)。

因此 TypeScript 4.0 支持了一個新的 ECMAScript 特性,添加了三個新的賦值運算符:&&=,||= 和 ??= 。

這些運算符很是適合替換下面這種代碼示例:
a = a && b;
a = a || b;
a = a ?? b;
或者像下面這樣的 if 代碼段:
// could be 'a ||= b'
if (!a) {
    a = b;
}
咱們甚至看到了一些模式,能夠在須要時懶惰地初始化值。
let values: string[];
// Before
(values ?? (values = [])).push("hello");
// After
(values ??= []).push("hello");
在極少數狀況下,你使用帶有反作用的 getter 或 setter 時,須要注意的是這些運算符僅在必要時執行賦值。從這個意義上講,"短路"的不只是運算符的右側,賦值自己也短路了。
obj.prop ||= foo();
// roughly equivalent to either of the following
obj.prop || (obj.prop = foo());
if (!obj.prop) {
    obj.prop = foo();
}
能夠試着運行 這個示例,看看它和老是執行賦值有什麼區別。
const obj = {
    get prop() {
        console.log("getter has run");
        // Replace me!
        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();

有關更多細節能夠查看拉取請求。

https://github.com/microsoft/TypeScript/pull/37727

你也能夠查看 TC39 的提案存儲庫。

https://github.com/tc39/proposal-logical-assignment/

catch 子句綁定支持 unknown
自 TypeScript 誕生以來,catch 子句變量始終按 any 類型化。這意味着 TypeScript 容許你對它們進行任何操做。
try {
    // ...
}
catch (x) {
    // x has type 'any' - have fun!
    console.log(x.message);
    console.log(x.toUpperCase());
    x++;
    x.yadda.yadda.yadda();
}
上述代碼會有一些沒法預期的行爲!因爲這些變量默認狀況下的類型爲 any,所以它們沒有任何類型安全性能夠防止無效操做。所以,TypeScript 4.0 如今容許你將 catch 子句變量的類型指定爲 unknown。unknown 比 any 更安全,由於它會在咱們操做值以前提醒咱們執行某種類型檢查。
try {
    // ...
}
catch (e: unknown) {
    // error!
    // Property 'toUpperCase' does not exist on type 'unknown'.
    console.log(e.toUpperCase());
    if (typeof e === "string") {
        // works!
        // We've narrowed 'e' down to the type 'string'.
        console.log(e.toUpperCase());
    }
}

儘管默認狀況下 catch 變量的類型不會更改,但咱們未來可能會考慮使用新的 --strict 模式標誌,以便用戶選擇啓用此行爲。同時,應該能夠編寫一個 lint 規則來強制 catch 變量具備以下顯式註解之一:: any 或: unknown。

有關更多信息,能夠查看拉取請求。

https://github.com/microsoft/TypeScript/pull/39015

定製 JSX 工廠

使用 JSX 時,fragment 是 JSX 元素的一種,容許咱們返回多個子元素。當咱們第一次在 TypeScript 中實現 fragment 時,咱們對其餘庫如何利用它們並不瞭解。現在,大多數鼓勵使用 JSX 和支持 fragment 的庫都具備相似的 API 設計。

在 TypeScript 4.0 中,用戶能夠經過新的 jsxFragmentFactory 選項來自定義 fragment 工廠。

例如,如下 tsconfig.json 文件告訴 TypeScript 以與 React 兼容的方式轉換 JSX,但將每一個工廠調用(invocation)切換爲 h 而不是 React.createElement,並使用 Fragment 而不是 React.Fragment。
{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment"
  }
}
若是須要基於各個文件使用不一樣的 JSX 工廠,則能夠利用新的 /**  @jsxFrag */ 註釋。例如,下面的內容:
// Note: these pragma comments need to be written
// with a JSDoc-style multiline syntax to take effect.
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from "preact";
let stuff = <>
    <div>Hello</div>
</>;
將輸出成這樣的 JavaScript:
// Note: these pragma comments need to be written
// with a JSDoc-style multiline syntax to take effect.
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from "preact";
let stuff = h(Fragment, null,
    h("div", null, "Hello"));

查看拉取請求以獲取更多信息。

https://github.com/microsoft/TypeScript/pull/38720

加快了 build 模式的速度

之前,使用 --noEmitOnError 標誌時,當先前的編譯在 --incremental 下出現錯誤,編譯速度將很是緩慢。這是由於基於 --noEmitOnError 標誌,上次編譯的任何信息都不會緩存在.tsbuildinfo 文件中。

TypeScript 4.0 對此進行了更改,從而在這些狀況下極大地提升了速度,進而改進了 --build 模式的場景(這意味着同時有 --incremental 和 --noEmitOnError)。

有關詳細信息,請查看拉取請求。

https://github.com/microsoft/TypeScript/pull/38853

帶有 --noEmit 的 --incremental

TypeScript 4.0 容許咱們在利用 --incremental 編譯時使用 --noEmit 標誌。之前不容許這樣作,由於 --incremental 須要發出.tsbuildinfo 文件。

有關詳細信息,請查看拉取請求。

https://github.com/microsoft/TypeScript/pull/39122

編輯器改進

TypeScript 編譯器不只能夠爲大多數主流編輯器提供較好的 TS 編輯體驗,還能夠改進 Visual Studio 系列編輯器的 JavaScript 開發體驗。

根據你使用的編輯器,在編輯器中使用新的 TypeScript/JavaScript 功能時會有區別:

  • Visual Studio Code 支持選擇不一樣版本的 TypeScript。另外,還有 JavaScript/TypeScript Nightly Extension 來緊跟最新版本(一般很是穩定)。

  • Visual Studio 2017/2019 有上面的 SDK 安裝程序和 MSBuild 安裝。

更多信息見 TS 編輯器支持列表。

https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support

轉換爲可選鏈

可選鏈是一項新功能,受到了普遍的歡迎。TypeScript 4.0 在轉換常見模式時能夠利用可選鏈和空值合併的優點!

咱們認爲這種重構應該能捕獲大多數用例的意圖,尤爲是當 TypeScript 對你的類型有更精確的瞭解時。

有關詳細信息,請查看拉取請求。

https://github.com/microsoft/TypeScript/pull/39135

/** @deprecated */ 支持

如今,TypeScript 的編輯支持能夠識別聲明中是否帶有/** @deprecated*/ JSDoc 註釋。該信息顯示在自動完成列表中,並做爲編輯器能夠特別處理的建議診斷。在像 VSCode 這樣的編輯器中,deprecated 的值一般顯示爲刪除線樣式。

有關詳細信息,查看拉取請求。

https://github.com/microsoft/TypeScript/pull/38523

啓動時的部分編輯模式

不少用戶抱怨啓動時間緩慢,尤爲是在大型項目中。具體來講,罪魁禍首一般是一個稱爲項目加載的過程,該過程與咱們編譯器的程序構建步驟大體相同。這一過程從一組初始文件開始,解析它們、解析它們的依賴、再解析那些依賴,解析那些依賴的依賴,等等,最後須要花費很長時間。項目越大,啓動延遲可能會越長。

因此咱們一直在努力爲開發人員提供一種新的模式,在得到完整的語言服務體驗以前提供部分體驗。這裏的核心思想是,編輯者能夠運行僅具備單個文件視圖的輕量級部分服務器。

這種新模式能夠將 TypeScript 在代碼庫上開始交互以前的準備時間從 20 秒到 1 分鐘縮短到只有幾秒鐘。好比說,在較大的代碼庫上重啓編輯器時,TS 3.9 版無法當即提供自動完成和快速信息;另外一方面,TS 4.0 能夠當即提供完整的編輯體驗,同時在後臺加載整個項目。

當前,惟一支持此模式的編輯器是 Visual Studio Code,但 UX 和功能仍有改進的餘地。咱們列出了準備加入的改進,但願得到更多反饋。

https://github.com/microsoft/TypeScript/issues/39035

有關更多信息,你能夠查看原始提案,拉取請求,以及後續的 meta 問題。

https://github.com/microsoft/TypeScript/issues/37713

更智能的自動導入

自動導入是一個了不得的功能。可是,自動導入在用 TypeScript 編寫的包上不起做用——也就是說,咱們得在項目的其餘位置至少寫了一個顯式導入。

爲何自動導入適用於 @types 軟件包,而不適用於使用本身類型的包呢?其實自動導入是經過檢查項目中已經包含的軟件包來實現的。TypeScript 有一個怪癖,能夠自動包括 node_modules/@types 中的全部包,而忽略其餘包;但爬取全部 node_modules 包的開銷可能會很昂貴。

當你嘗試自動導入剛剛安裝但還沒有使用的內容時,這些都會致使糟糕的體驗。

TypeScript 4.0 如今能夠包含你在 package.json 的 dependencies(和 peerDependencies)字段中列出的包。這些包中的信息僅用於改進自動導入,不會更改類型檢查等其餘內容。這樣就避免了遍歷 node_modules 目錄的成本,使咱們能夠爲全部帶類型的依賴項提供自動導入。

當你的 package.json 列出了超過十項還沒有導入的類型化依賴項時,這個功能會自動禁用,以免緩慢的項目加載過程。要強制開啓它或徹底禁用它,你能夠配置編輯器。在 Visual Studio Code 中是"Include Package JSON Auto Imports"設置(或 typescript.preferences.includePackageJsonAutoImports)。

有關詳細信息,能夠查看提案問題以及拉取請求。

https://github.com/microsoft/TypeScript/issues/37812

咱們的新網站!

TypeScript 網站最近被完全重寫了!

詳細信息能夠參考以前的文章:

《TypeScript 新版網站上線:帶來了新的導航機制》

重大更改
lib.d.ts

咱們的 lib.d.ts 聲明已更改,具體來講是 DOM 的類型已更改。主要是刪除了 document.origin,它僅在 IE 的舊版本中有效,而 Safari MDN 建議改用 self.origin。

屬性重寫訪問器(反之亦然)是錯誤
之前,只有在使用 useDefineForClassFields 時,屬性重寫訪問器或訪問器重寫屬性是一個錯誤;但如今,在派生類中聲明一個將重寫基類中的 getter 或 setter 的屬性時老是發出錯誤。

class Base {
    get foo() {
        return 100;
    }
    set foo() {
        // ...
    }
}
class Derived extends Base {
    foo = 10;
//  ~~~
// error!
// 'foo' is defined as an accessor in class 'Base',
// but is overridden here in 'Derived' as an instance property.
}

class Base {
    prop = 10;
}
class Derived extends Base {
    get prop() {
    // ~~~~
    // error!
    // 'prop' is defined as a property in class 'Base', but is overridden here in 'Derived' as an accessor.
        return 100;
    }
}

有關詳細信息,查看拉取請求。

https://github.com/microsoft/TypeScript/pull/37894

delete 的操做數必須是可選的
在 strictNullChecks 中使用 delete 運算符時,操做數如今必須爲 any、unknown、never 或爲可選(由於它在類型中包含 undefined)。不然,使用 delete 運算符是錯誤的。
interface Thing {
    prop: string;
}
function f(x: Thing) {
    delete x.prop;
    // ~~~~~~
    // error! The operand of a 'delete' operator must be optional.
}

關於更多信息,查看拉取請求。

https://github.com/microsoft/TypeScript/pull/37921

TypeScript 的 Node 工廠用法已棄用

現在,TypeScript 提供了一組用於生成 AST 節點的「工廠」函數。可是,TypeScript 4.0 提供了新的 node 工廠 API。所以 TypeScript 4.0 決定棄用使用這些舊函數,推薦改用新函數。

有關更多信息,請查看拉取請求。

https://github.com/microsoft/TypeScript/pull/35282

下一步計劃

TypeScript 4.1 的迭代計劃已經上線了,你能夠大體瞭解一下。

https://github.com/microsoft/TypeScript/issues/40124

同時,你能夠在工做區或編輯器中使用 nightly 構建來預覽 4.1 中添加的新特性。不管你是在使用 TypeScript 4.0 仍是下一版本,咱們都但願聽到你的反饋!能夠經過 Twitter 聯繫咱們,或在 GitHub 上發起問題。

咱們再一次爲社區所作的一切工做和奉獻精神深表感謝。咱們但願讓 TypeScript 和 JavaScript 的編碼體驗成爲你應得的純粹樂趣。爲此,咱們須要改善語言和編輯體驗、提高性能、迭代咱們的用戶體驗、下降入門和學習的門檻等等。

很是感謝你們,請享用 4.0 版本吧,編程愉快!

延伸閱讀

https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/

學習交流

  • 關注公衆號【前端宇宙】,每日獲取好文推薦
  • 添加微信,入羣交流

「在看和轉發」 就是最大的支持

本文分享自微信公衆號 - 前端宇宙(gh_8184da923ced)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索