原生JS以後也支援型別註解啦?

卡頌發表於2022-07-07

大家好,我卡頌。

布達佩斯2022 JSConf會議上,tc39(ES標準委員會)成員Gil Tayar介紹了一份當前仍處於stage 1階段的提案 —— Type Annotations,意在讓原生JS支援型別註解。

Gil Tayar

換句話說,如果提案通過,很多.ts檔案將字尾改為.js後就能直接在瀏覽器中執行。

一份tc39提案通常會經歷5個階段:

  • stage 0:被提出
  • stage 1:接受審議
  • stage 2:規範基本完成
  • stage 3:等待被實現
  • stage 4:納入語言標準中

所以Type Annotations當前仍處於接受審議的狀態。

但是提案發起者Gil Tayar對這份提案的通過很有信心,本文我們來聊聊這份提案的相關內容。

歡迎加入人類高質量前端框架群,帶飛

為什麼需要原生型別註解?

根據20年、21年state of JS的統計,靜態型別高票當選JS中當前最欠缺的功能

同時,在Github報告中,TS被列為第四大最常用的語言

所以,對前端工程師來說,型別註解需求很大。

那麼,既然已經有了TS,為什麼還需要原生JS支援型別註解呢?

通常來說,從開發者編寫的原始碼線上生產環境程式碼間需要經過程式碼編譯

程式碼編譯主要包括兩個步驟:

  1. 降級編譯(包括高階語法轉換為低階語法,高階方法的polyfill
  2. 程式碼轉譯(比如壓縮、混淆、tree-shaking、型別擦除)

所謂型別擦除,是指擦除程式碼中的型別註解,讓其變成符合原生JS規範的程式碼,比如:

// 擦除前
function add(a: number, b: number): number {
  return a + b;
}
// 擦除後
function add(a, b) {
  return a + b;
}

隨著時間的推移,各主流瀏覽器相容性越來越好,步驟1在可預見的未來重要性會逐漸降低。

對於TS開發者,從原始碼線上生產環境程式碼間可能只需要型別擦除

如果原生JS支援型別註解,就能省去型別擦除對應的編譯流程,讓程式碼更容易在宿主環境執行。

和TS的關係

這份提案的目的,並不是另起爐灶,獨立實現一套原生JS的型別註解。而是與TS團隊合作,提出一套合適的規範。

新的規範與TS規範的關係類似下圖:

一方面,Type Annotations提案從TS中借鑑了很多特性,這就是圖中相交的部分。

你可以到grammar-conventions看到規範當前定義的型別

另一方面,TS迭代速度很快,新的特性產出很快。而Type Annotations作為JS語言的一部分,迭代會更加保守,所以TS中一些特性在Type Annotations中並不支援。

此外,TS中一些結構(比如EnumsNamespaces)存在執行時的語義,Type Annotations也不會支援。

這些就是TS中存在,而Type Annotations中不存在的部分。

最後,Type Annotations設計的初衷並不是與TS強繫結,而僅僅是提供一套型別規範,開發者編寫程式碼時的型別檢查還是由各種型別檢查器(比如TSFlow)實現。

所以,Type Annotations還有一部分特性是TS當前未定義的,這也是為了規範更廣泛的適用性考慮的,也就是圖中Type Annotations存在,而TS不存在的部分。

這部分特性需要TS後續實現,這也是為什麼Type Annotations要與TS團隊合作的一大原因。

對開發者意味著什麼

如果Type Annotations最終出現在ES20xx版中,屆時開發者編寫程式碼的步驟是:

  1. 選擇合適的型別檢查器(比如TS),這個型別檢查器需要完全遵循Type Annotations規範(而不是自己的規範,比如TS規範)
  2. 編寫帶型別宣告的原生JS程式碼
  3. 型別檢查器會檢查型別錯誤,並給予報錯或提示

對於如下原生JS程式碼,如果開發者傳入了錯誤的型別,JS會報錯麼?

function add(a: number, b: number): number {
  return a + b;
}

// 錯誤的型別傳參
add('KaSong', 123);

答案是:不會。

Type Annotations僅僅是一套規範,該規範由各種型別檢查器執行。

JS的宿主環境(比如瀏覽器)在執行帶型別宣告的JS程式碼時,會忽略型別宣告。

總結

有同學可能會問:就為了減少編譯時型別擦除這一步,就提出原生型別規範,有必要麼?

甚至當Type Annotations落地後,開發者上線前在進行程式碼壓縮時,型別擦除也會作為程式碼壓縮的職責之一。

從這個角度看,甚至沒有減少編譯時的工作量。

所以提出原生的型別規範,有必要麼?

前端的發展實際是一個努力去編譯時流程的過程。

比如,編譯時程式碼需要降級,需要polyfill?隨著IE11停止服務,主流瀏覽器紛紛跟進標準落地,降級與polyfill的需求逐漸變少。

再比如,程式碼需要打包?隨著ESM規範落地,在當前,至少在開發環境中程式碼已經不需要打包(使用Vite)。

Type Annotations的出現,就是遵循努力去編譯時流程這一趨勢的產物。

從這個角度看,還是很有必要的。

相關文章