楠木軒

TypeScript 4.0發佈,新增可變參數元組類型等

由 卯秀珍 發佈於 科技

昨天微軟TypeScript宣佈發佈TypeScript 4.0版本。作為一個大版本發佈,大家一定很關心其帶來的變化和改善。請和蟲蟲一起探索。

概述

TypeScript 是現代JavaScript生態圈核心部分,是有程序員大神,安德斯.哈爾斯伯格,在繼Delphi,J++,.net和C++之後又一個語言。是微軟奉獻給開源社區的神器之一。在npm上,在上個月,2020年7月TypeScript首次突破了每月超過5000萬的下載量。

StackOverflow的最新開發人員調查中,TypeScript定位為第二受歡迎的語言(第一是Rust)。

在最新的JS調查狀況中,大約89%的使用TypeScript的開發人員表示會再次使用它。

TypeScript是一種通過添加靜態類型的語法在JavaScript之上構建的語言。這個想法是,通過記下值的類型以及它們的使用位置,可以使用TypeScript對代碼進行類型檢查,並在運行代碼之前(甚至在保存文件之前)獲得有關錯誤的信息。還可以使用TypeScript編譯器從代碼中剝離類型,並提供可在任何地方運行的簡潔易讀的JavaScript。

除了檢查之外,TypeScript還使用靜態類型來支持強大的編輯器工具,例如自動完成,代碼導航,重構等。在Visual Studio Code或Visual Studio等編輯器中使用過JavaScript,那麼已經在使用由類型和TypeScript提供支持的體驗。

大版本變化總結

自從3.0開始TS發生了很多變化,首先TypeScript 3.0本身帶來大量改善,統一元組類型和參數列表是一大亮點,可在函數上啓用大量現有的JavaScript模式。該發行版還提供了項目參考,以幫助擴展,組織和共享代碼庫。產生重大影響的一個小變化是3.0引入了類型安全的替代,any稱為unknown。

TypeScript 3.1擴展了映射類型的功能以處理元組和數組類型,並極大地簡化了將屬性附加到函數的過程,而無需訴諸於已失效的TypeScript特定運行時功能。

TypeScript 3.2 允許泛型類型的對象,並通過嚴格的輸入leveraged 3.0,以更好的模型元編程與功能bind,call以及apply相結合。

TypeScript 3.3在3.2之後遵循一些穩定性,但是在使用聯合類型方法時還帶來了生活質量的改進,並在模式下增加了文件增量構建。--build

TypeScript 3.4,進一步傾向於支持功能模式,更好地支持不可變數據結構,並改進了對高階通用函數的推斷。最大的亮點是引入了flag,它是一種避免每次運行TypeScript都完全重建而無需項目引用的方法,從而可以更快地進行編譯和類型檢查。--incremental

TypeScript 3.5和3.6,加強了一些類型系統規則,以及更智能的兼容性檢查規則。

TypeScript 3.7是一個非常值得關注的版本,因為它具有新類型系統功能與ECMAScript功能的豐富結合。在類型系統方面,引入了遞歸類型別名引用和對斷言樣式函數的支持,這兩者都是獨特的類型系統功能。從JavaScript來看,該版本帶來了可選的鏈接和合並功能,這是TypeScript和JavaScript用户最迫切的兩項功能。

,3.8和3.9帶來了僅類型的導入/導出,以及ECMAScript功能,例如私有字段,await模塊中的頂層以及新語法。這些版本還提供了性能和可伸縮性優化。

4.0新功能概述

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

也可以通通VS 2019/2017和VSC版本內置獲得。

可變參數元組類型

想象JavaScript中的一個函數,該函數concat採用兩個數組或元組類型並將它們連接在一起以創建一個新數組。

還有tail,它接受一個數組或元組,並返回除第一個元素外的所有元素。

如何在TypeScript中鍵入其中一個?

對於concat,在較舊版本的語言中唯一可以做的就是編寫重載。

第二個數組始終為空時的七個重載。arr2有一個參數的情況:

很明顯,這已經變得不合理了。不幸的是,鍵入像這樣的函數也會遇到tail同樣的問題。

還有另外一種情況,被稱為"一千個重載死亡",它甚至不能解決一般問題。它只為想寫的重載給出正確的類型。如果想做一個包羅萬象的案例,則需要像下面這樣的重載:

但是,使用元組時,該簽名不會對輸入的長度或元素的順序進行任何編碼。

TypeScript 4.0帶來了兩個基本改善,並在推理方面進行了改進,使鍵入這些內容成為可能。

第一個變化是元組類型語法中的傳播現在可以通用。這樣即使不知道要操作的實際類型,也可以表示元組和數組的高階操作。當在這些元組類型中實例化通用擴展時(或用實型替換),它們可以產生其他數組和元組類型集。

例如,可以在TS 4.0中鍵入像這樣的函數tail,而不會出現"一千個重載死亡"的問題。

第二個變化是,其餘元素可以出現在元組中的任何位置,而不僅僅是在結尾。

之前,TypeScript會發出如下錯誤:

A rest element must be last in a tuple type.

TypeScript 4.0可以放寬此限制。

請注意,在沒有已知長度的類型的情況下,結果類型也將變得不受限制,並且所有以下所有元素都將成為結果其餘元素類型。

通過將這兩種功能結合在一起,就可以很便捷的編寫一個類型正確的簽名

儘管一個簽名仍然有些冗長,但這只是一個簽名,不必重複,它可以在所有數組和元組上提供可預測的行為。

功能本身很棒,但在更復雜的場景中也很有用。例如,函數partialCall的部分應用名為的參數。partialCall帶有一個函數f以及幾個初始的期望參數,返回一個新函數,該函數接受f仍需要的任何其他參數,並f在接收到它們時進行調用。

TS 4.0改進了rest參數和rest tuple元素的推斷過程,使其"正常工作":

partialCall瞭解其初始可以使用和不能使用的參數,並返回可以接受和拒絕的函數。

可變參數元組類型啓用了許多新的令人興奮的模式,尤其是在函數組成方面,可以利用它來做更好的工作,以檢查JavaScript的內置bind方法的類型。

元組元素標籤

改善元組類型和參數列表非常重要,圍繞常見的JavaScript習慣用法進行強類型驗證。實際上只是對參數列表進行切片和切塊並將它們傳遞給其他函數。可以使用元組類型作rest參數的想法很有意義。

例如,以下使用元組類型作為參數的函數

差異有:可讀性。在第一個示例中,沒有第一個和第二個元素的參數名稱。儘管這些對類型檢查沒有影響,但元組位置上缺少標籤會使其更難使用,難以傳達意圖。

這就是為什麼要在TypeScript 4.0中,元組類型需要提供標籤了。

為了加深參數列表和元組類型之間的聯繫,其餘元素和可選元素的語法與參數列表的語法相同。

使用帶標籤的元組時有一些規則。例如,當標記一個元組元素時,還必須標記該元組中的所有其他元素。

值得注意的是,標籤不需要在解構時以不同的方式命名變量。它們純粹是那裏的文檔和工具。

總的來説,帶標籤的元組在利用元組和參數列表周圍的模式以及以類型安全的方式實現重載時很方便。實際上,TypeScript的編輯器支持會在可能的情況下嘗試將它們顯示為重載。

構造函數的類屬性推斷

當noImplicitAny啓用時,TypeScript 4.0可以使用控制流分析來確定類中的屬性類型。

如果並非將構造函數的所有路徑都分配給實例成員,則該屬性可能被認為是undefined。

短路分配運算符

JavaScript和許多其他語言一樣支持一組稱為複合賦值運算符的運算符。複合賦值運算符將一個運算符應用於兩個參數,然後將結果賦給左側。比如:

JavaScript中的許多運算符都有對應的賦值運算符!但是仍然存在三個值得注意的例外操作符:邏輯和(&&),邏輯或(||)和無效合併(??)。

TS 4.0新引入一個新的ECMAScript功能添加三個新的賦值操作符:&&=,||=,和??=。

這些運算符非常適合替換用户可能編寫如下代碼的任何示例:

甚至一些模式支持惰性初始化,只有在需要它們時才加載。

在極少數情況下使用帶有副作用的getter或setter時,值得注意的是這些運算符僅在必要時執行賦值。從這個意義上講,不僅操作符的右側"短路"了,賦值本身也是如此。

catch語句中綁定unknown

自TypeScript誕生以來,catch子句變量始終為any。TypeScript允許對它們進行任何操作。

如果試圖防止在錯誤處理代碼中發生更多錯誤,則上面的代碼會有一些不良行為!因為這些變量any默認情況下具有類型,所以它們缺少類型安全性,這些類型安全性可能在無效操作上出錯。

TypeScript 4.0允許指定catch子句變量的類型unknown。unknown比any它更安全,在對值進行運算之前,需要執行某種類型檢查。

儘管catch默認情況下變量的類型不會更改,但將來可能會考慮使用新的模式標誌,以便用户可以選擇這種行為。同時,應該可以編寫lint規則來強制變量具有或的顯式註釋。

定製JSX工廠

使用JSX時,片段是JSX元素的一種,它允許返回多個子元素。大多數鼓勵使用JSX和支持片段的其他庫都具有類似的API形狀。

TypeScript 4.0中,用户可以通過新jsxFragmentFactory選項來自定義片段工廠。

例如,下面代碼實現和React兼容的方式轉換JSX,但將每個工廠調用切換為而不是,並使用代替。

如果需要基於每個文件使用不同的JSX,則可以利用新的/** @jsxFrag */註釋。例如,

build模式下的速度改進--noEmitOnError

以前,使用該標誌時,在先前編譯時出現錯誤而導致的程序之後編譯程序將非常慢。這是因為來自上一次編譯的任何信息都不會基於該標誌被緩存在文件中。--incremental--noEmitOnError.tsbuildinfo--noEmitOnError

TypeScript 4.0對此進行了更改,從而在這些情況下極大地提高了速度,並進而改善了模式情況(這意味着和)。

--incremental與--noEmit

TypeScript 4.0允許在利用編譯時使用該標誌。以前不允許這樣做。但是,啓用更快的增量構建的用例足夠重要,可以為所有用户啓用。

編輯器改進

TypeScript編譯器不僅可以為大多數主要編輯器提供TypeScript本身的編輯體驗,還可以為Visual Studio系列編輯器等提供JavaScript體驗。根據編輯器,在編輯器中使用新的TypeScript/JavaScript功能會有所不同,但是

Visual Studio Code支持選擇不同版本的TypeScript。另外,還有JavaScript /TypeScript Nightly Extension可以保持最新發展(通常非常穩定)。

Visual Studio 2017/2019具有上述SDK安裝程序和MSBuild安裝程序。

轉換為可選鏈接

可選鏈接是一項新功能,受到了廣泛的歡迎。這就是為什麼TypeScript 4.0帶來了新的重構來轉換常見模式以利用可選鏈接和無效合併的原因!

Converting a && a.b.c && a.b.c.d.e.f() to a?.b.c?.d.e.f.(), image

請記住,儘管由於JavaScript中真實性/虛假性的微妙之處,這種重構不能完美地捕獲相同的行為,但它應該捕獲大多數用例的意圖,尤其是當TypeScript對類型有更精確的瞭解時。

/** @deprecated */支持

TypeScript的編輯支持現在可以識別使用/** @deprecated *JSDoc註釋標記的聲明。該信息顯示在完成列表中,並作為編輯器可以特別處理的建議診斷。在VS Code這樣的編輯器中,不建議使用的值通常顯示為"觸擊式"樣式。

啓動時的部分語義模式

在大型項目中程序構建的過程從初始的一組根文件開始,進行解析,查找其依賴項,解析這些依賴項,查找那些依賴項的依賴項,等等。項目越大,獲得基本的編輯器操作(如轉到定義或快速信息)的時間就越長。

編輯器可以運行輕量級的部分服務器,該服務器僅查看編輯器已打開的當前文件。

很難確切地説出將看到什麼樣的改進,但有趣的是,TypeScript在Visual Studio Code代碼庫上變得完全響應之前,通常需要20秒到一分鐘的時間。相比之下,新的部分語義模式似乎將延遲降低了幾秒鐘。

在特別大的代碼庫上重新啓動兩個編輯器時,帶有TypeScript 3.9的編輯器根本無法提供完成功能或快速信息。另一方面,儘管在後台加載了整個項目,但具有TypeScript 4.0的編輯器可以立即為正在編輯的當前文件提供豐富的體驗。

當前,唯一支持此模式的編輯器是Visual Studio Code,Visual Studio Code Insiders中將對UX進行一些改進。

更智能的自動導入

自動導入是一個了不起的功能,它使編碼變得容易得多。之前自動導入對用TypeScript編寫的依賴項不起作用。需要在項目的其他位置至少寫了一個明確的導入。

為什麼自動導入適用於@types軟件包,但不適用於運送自己類型的軟件包?事實證明,自動導入僅適用於項目已包含的軟件包。由於TypeScript具有一些古怪的默認值,這些默認值會自動將軟件包添加到項目中,因此這些軟件包將被自動導入。另一方面,其他軟件包被排除在外,因為在所有軟件包中進行爬網確實非常昂貴

當嘗試自動導入剛剛安裝但尚未使用的某些內容時,所有這些都會導致非常糟TS4.0現在確實在編輯情景一些額外的工作,包括已經在你列出的軟件包的(和)領域。這些包中的信息僅用於改進自動導入,不會更改類型檢查等其他內容。能夠為所有具有類型的依賴項提供自動導入,而不會產生完整搜索的費用。

在極少數情況下,當列出尚未導入的十多個類型化依賴項時,此功能會自動禁用自身,以防止緩慢的項目加載。要強制功能正常運行或完全禁用它,應該能夠配置編輯器。對於Visual Studio Code,這是"包含包JSON自動導入"(或)設置。

新站點

TypeScript網站最近被徹底重寫並推出!