大家好,我卡颂。
在布达佩斯2022 JSConf[1]会议上,tc39[2](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[3]的统计,「静态类型」高票当选「JS中当前最欠缺的功能」。
同时,在Github报告[4]中,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[5]看到规范当前定义的类型
另一方面,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
的出现,就是遵循「努力去编译时流程」这一趋势的产物。
从这个角度看,还是很有必要的。
参考资料
[1]
布达佩斯2022 JSConf: https://www.youtube.com/watch?v=SdV9Xy0E4CM&list=PL37ZVnwpeshGuMZrOZzEo8QLBjjpbtBGm&index=2
[2]
tc39: https://github.com/tc39
[3]
state of JS: https://stateofjs.com/en-us/
[4]
Github报告: https://octoverse.github.com/
[5]
grammar-conventions: https://tc39.es/proposal-type-annotations/grammar.html#grammar-conventions