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

今天,微軟宣佈 TypeScript 4.0 正式版上線了!這一新版本深入改進了表現力、生產力和可伸縮性,是 TypeScript 語言的新一代版本。

今天,我們很高興地宣佈TypeScript 4.0正式版終於上線了!它是我們深入改進表現力、生產力和可伸縮性的結果,是TypeScript語言的新一代版本。

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

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

如果你已經在項目中使用TypeScript,則可以通過NuGet獲取它,也可以通過以下命令使用npm獲取:

npm install -D typescript 

你還可以通過以下方式獲得編輯器支持:

4.0之旅

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

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

從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體驗的基礎,這樣一個繁忙而熱情的社區在不斷改善我們的生態系統,並推動我們不斷改進,我們對此表示感謝。

新內容

  • 可變元組類型

  • 標記的元組元素

  • 構造器的類屬性推斷

  • 短路賦值運算符

  • catch子句綁定unknown

  • 定製JSX工廠

  • 加快了帶有–noEmitOnError的build模式的速度

  • 帶有–noEmit的–incremental

  • 編輯器改進

    • 轉換爲可選鏈
    • /** @depreacted */支持
    • 啓動時的部分編輯模式
    • 更智能的自動導入
  • 我們的新網站!

  • 重大更改

可變元組類型

考慮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方法的類型檢查。此外還有其他一些推斷改進和模式,想了解更多信息,可以查看可變元組的拉取請求

標記的元組元素

改善元組類型和參數列表的體驗很重要,因爲它使我們能夠圍繞常見的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的編輯器支持會在可能的情況下將它們顯示爲重載。

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

構造器的類屬性推斷

當啓用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; 
    } 
} 

更多信息請見拉取請求

短路賦值運算符

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(); 

有關更多細節可以查看拉取請求。你也可以查看TC39的提案存儲庫

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。
有關更多信息,可以查看拉取請求

定製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")); 

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

加快了帶有–noEmitOnError的build模式的速度

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

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

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

帶有–noEmit的–incremental

TypeScript 4.0允許我們在利用–incremental編譯時使用–noEmit標誌。以前不允許這樣做,因爲–incremental需要發出.tsbuildinfo文件。

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

編輯器改進

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

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

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

轉換爲可選鏈

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

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

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

/** @deprecated */支持

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

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

啓動時的部分編輯模式

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

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

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

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

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

更智能的自動導入

自動導入是一個了不起的功能。但是,自動導入在用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)。

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

我們的新網站!

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; 
    } 
} 

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

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. 
} 

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

TypeScript的Node工廠用法已棄用

如今,TypeScript提供了一組用於生成AST節點的“工廠”函數。但是,TypeScript 4.0提供了新的node工廠API。因此TypeScript 4.0決定棄用使用這些舊函數,推薦改用新函數。

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

下一步計劃

TypeScript 4.1的迭代計劃已經上線了,你可以大致瞭解一下。同時,你可以在工作區或編輯器中使用nightly構建來預覽4.1中添加的新特性。無論你是在使用TypeScript 4.0還是下一版本,我們都希望聽到你的反饋!可以通過Twitter聯繫我們,或在GitHub上發起問題

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

非常感謝大家,請享用4.0版本吧,編程愉快!

原文鏈接:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章