大家好,我卡頌。
在布達佩斯2022 JSConf會議上,tc39(ES標準委員會)成員Gil Tayar介紹了一份當前仍處於stage 1
階段的提案 —— Type Annotations
,意在讓原生JS
支援型別註解。
換句話說,如果提案通過,很多.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
支援型別註解呢?
通常來說,從開發者編寫的原始碼到線上生產環境程式碼間需要經過程式碼編譯。
程式碼編譯主要包括兩個步驟:
- 降級編譯(包括高階語法轉換為低階語法,高階方法的
polyfill
) - 程式碼轉譯(比如壓縮、混淆、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
中一些結構(比如Enums
、Namespaces
)存在執行時的語義,Type Annotations
也不會支援。
這些就是TS
中存在,而Type Annotations
中不存在的部分。
最後,Type Annotations
設計的初衷並不是與TS
強繫結,而僅僅是提供一套型別規範,開發者編寫程式碼時的型別檢查還是由各種型別檢查器(比如TS
、Flow
)實現。
所以,Type Annotations
還有一部分特性是TS
當前未定義的,這也是為了規範更廣泛的適用性考慮的,也就是圖中Type Annotations
存在,而TS
不存在的部分。
這部分特性需要TS
後續實現,這也是為什麼Type Annotations
要與TS
團隊合作的一大原因。
對開發者意味著什麼
如果Type Annotations
最終出現在ES20xx
版中,屆時開發者編寫程式碼的步驟是:
- 選擇合適的型別檢查器(比如
TS
),這個型別檢查器需要完全遵循Type Annotations
規範(而不是自己的規範,比如TS
規範) - 編寫帶型別宣告的原生
JS
程式碼 - 型別檢查器會檢查型別錯誤,並給予報錯或提示
對於如下原生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
的出現,就是遵循努力去編譯時流程這一趨勢的產物。
從這個角度看,還是很有必要的。