14

未来可期的TypeScript

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=Mzg2NDAzMjE5NQ%3D%3D&%3Bmid=2247485509&%3Bidx=1&%3Bsn=ce489af9a81aa0e66e913367a18967f2
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

qQBRnyv.jpg!web作者: 腾讯@IMWeb  | 编辑: 前端妹

mp.weixin.qq.com/s/spDb_m2I1tbhIaJlg4Bpng

IMWeb 团队隶属腾讯公司,是国内最专业的前端团队之一。专注前端领域多年,负责过 QQ 资料、QQ 注册、QQ 群等亿级业务。目前聚焦于在线教育领域,精心打磨 腾讯课堂、企鹅辅导及ABCmouse三大产品。

正文从这开始~~

讲述了自己从一名 TypeScript 抵制者转变为支持者的心路历程,以及 TypeScript 在在线教育团队中的实践经验,并对团队新项目是否该引入 TypeScript、如何快速搭建、以及现有项目如何向 TypeScript 迁移提供策略性建议与方案。

2019年,越来越多的知名前端开源项目选择使用 TypeScript 做为其新版本的开发语言,TypeScript 的社区支持也日趋完善,VS Code + TypeScript 的组合拳让不少原本持怀疑,甚至抵制态度的前端开发者们不禁喊出“真香!”。

然而,无论是在大公司还是中小型公司中,依旧有相当多的前端工程师对TS有着理解偏差。TS的官方文档也过于技术性,并没有对TS的诞生原因,所要解决的问题等做细致的解释。所以本次演讲并不会关注太多TS本身的语法,高级用法这类话题,因为在这些方面,官方文档是更好的资料来源。而希望听众在分享结束后,能更明白TS成功的背后,究竟是解决了哪些问题?它的核心是什么?它的与众不同之处在哪?团队是否该引入TS以及如何引入?

如何定义TypeScript

官方定义

imUFvmz.jpg!web

TS官网下的定义为“JavaScript that scales”,这句话如果翻译为中文不是一件简单的事。Scales意味着“规模扩大”。而对应的中文官网直接翻译成“JavaScript的超集",显然是有点文不对题的。

然而,这却恰好从两个不同的层面解释了什么是TypeScript。

英文版告诉你,TS与JS的能力区分在哪:即TS更能适应项目规模不断扩大的场景。

中文版告诉你,TS的本质是什么:即它是一种具有类型系统的JS的超集。

不仅仅是一门语言

eIF3EzR.jpg!web

如果你觉得定义本身比较空洞,想要更简单直接的了解TS是什么,不如看看它带来了什么。

作为一门语言本身来说,首先带来的是类型安全,可以类比java,c++。

另外,TS包含一个编译器,通过来你可以使用最新最稳定的JS特性,功能类似babel。

最后,最核心的部分,由于ts带来类型,所以你的工具,IDE可以更容易的理解你的代码。从而可以创造很多工具,来帮助你更高效的写高质量的代码。

所以总结起来TS不仅仅是一门语言,而是生产力工具。

JS世界的傲慢与偏见

说到TS,就不得不提JS,JS作为一门非常有争议的语言,发展到今天成为当下最流行的语言的过程是非常戏剧性的。

有很多必然,也有很多偶然。前端社区有关js的争论,也一天没有消停过,那我们就来看一下js的世界里有哪些有趣的话题。

开发者的偏见

FnauEna.jpg!web

在过去,很多人把JS当做是一个玩具语言。我们也会发现在某些场景,使用JS的人员并不一定是开发者(譬如早期qq空间通过脚本装饰页面)。更可以毫不夸张的说,很多开发者觉得,JS是一门,等真正需要用到的时候,再去随意学学,就能上手的语言。种种原因导致了JS在很多时候被滥用。

偏见的背后

imuMviV.jpg!web

当然JS本身的确是存在非常多的问题,尤其在早期的时候。没有模块、class、类型。还有一堆为人所诟病的语言设计,null、undefined、NaN等等。

开发者是如何应对JS的种种问题的

aQzYBr2.jpg!web

虽然JS有诸多糟粕,但是在浏览器里,你没办法摆脱他。“聪明”的开发者们想出了“用我喜欢的语言来编译生成JS”这样的点子,把JS仅仅当作媒介语言。你几乎可以找到任何语言的版本,这其中有像Google的GWT,微软的Script#都是被大规模在正式环境中应用的产品。

慢慢的,一些“更聪明”的开发者觉得这种方式有点不伦不类,不如彻底一点,干脆发明一些新的语言来取代JS。这里面最为出名的就是Google的Dart与CoffeeScript。

取代的结果如何

reaIvyZ.jpg!web

在google trend中,如果把CoffeeScript、Dart、TypeScript一起搜索。可以看到,从2014年至今,CoffeeScript与Dart基本没掀起任何波浪,而TS迎头直上。

从失败中吸取教训

VjqIJje.jpg!web

为什么TS可以,而其他这些语言却没法成为主流呢?这其中主要有三个原因:

1、没有严格遵从ECMAScript的规范。语法层面他们和JS是完全割裂的。譬如CoffeeScript用的是接近于ruby的语法,当使用这样的语言的时候,你会感觉你是完全在学一门新语言。有一定的学习成本。在ECMAScript规范不断演进的情形下,这类语言的语法就会越来越成为累赘。

2、性能问题。这在早期的时候更为明显。图中的一段Dart代码,在用Dart的编译器转化为JS后,不做任何优化的情况下,居然产生了10000多行代码。这显然是难以接受的。

3、生成代码的可读性差,没有办法回退。毕竟只是把JS做为媒介语言,JS的可读性不是这类语言的考量。这也意味着一旦项目启动,就没法很轻松的回退回原生JS。

来自开发者的傲慢

坊间流言

zauEfmV.jpg!web

基于种种原因,开发者们越来越倾向于写原生JS。HTML5,Nodejs,还有像Angular,React,Vue这样优秀的前端框架又把JS的使用推向另一个高度。每一个JS开发者都无比的振奋。于是,渐渐的,我们又听到了另外一种声音。

1、凡是可以用JS来写的应用,最终都会用JS来写--At Woods定律。

2、js是最好的语言,反正你们饶了一圈最后都会回来。

3、微软出的东西,能行么?

被微软狠狠打脸

UniUZvy.jpg!web

目前在github上热度前十的项目中,微软直接占了两席。而排在第八位的,也是社区中TS的周边产物。

ERNBfmr.jpg!web

StackOverFlow的报告,在程序员最喜欢的语言中,TS与Python目前并列第二,仅次于Rust。

AzQFRra.jpg!web

Npm包的开发者中,高达62%的开发者在使用TS。

从这些数字中可以很明显的看出,当下TS已经取得了相当惊人的成就。

为何TS会取得如此成功

IbMjia7.jpg!web

TS会取得如此成功主要有5个原因:

1、对类型安全的诉求。无论在浏览器还是服务端,前端项目规模越来越大,越来越复杂。而规模越大,对静态类型语言的诉求就越强烈。

2、严格遵守ECMAScript规范。与那些把JS当作媒介语言的语言是不同的。TS选择改进了JS,而不是取代它。学习ts语法并不会增加额外成本。

3、采用Structural Typing而不是Nominal Typing。面向对象的语言,一般使用nominal typing(C++, Java, Swift),而函数式语言更习惯使用Structural Typing(OCaml, Haskell, Elm)。JS里面,你即可以使用面向对象,又可以使用函数式。但js的开发者通常更倾向于使用函数式编程。这种情况下,TS选择了使用结构类型,也更符合js开发者的编程习惯。

4、强大的开发工具。正如我前面提到的,通过工具提高生产力才是TS的核心目标。TS本身提供了非常棒的工具支持,他的TS Server机制是非常有创造性的(后面会详述)。

5、Open Source, Open Development。TS是以100%的开放开发的方式来运营的。也就是说有关与ts的一切,都是对开发者100%透明的。在过去,当你给一门语言提一个bug的之后,可能等一两年才会出新版本,而到那个时候你才会发现,你提的bug可能根本没被修复。通过TS的roadmap你可以清晰的看到具体哪些bug会被修复,哪些feature会被新增,以及所有关于这些技术点的讨论。这样拉近了核心开发团队与使用者的距离,让TS的社区非常的活跃。

腾讯在线教育选择TS的四个理由

理由一:更少的Bug

研究与实践

i2miqy7.jpg!web

要具体的量化这个减少bug的百分比,不是一件容易的事。

不过伦敦大学与微软研究院的一些学者,发表了一篇相当有影响力的论文。文中指出,15%的github 公开bug,是可以通过Typescript来规避的。而根据在线教育TS使用的实际经验,数据统计,我们发现超过30%的bug都可以通过类型安全来规避。

为什么达到30%

B3IJZbi.jpg!web

业务中的通常bug可以被分为两类,一类是类型错误(type error)引发的bug,这部分错误中的大多数是可以通过ts来避免的。

另一类是实现错误(spec error)引发的bug,比如对需求没有理解透彻,导致做出来的功能不符合预期,或者有逻辑bug。所以TS能减少的具体的bug比例数字,与类型错误引起的bug在项目总体中的比例有关。

理由二:提高生产力

如何提高生产力

6nu2AvE.jpg!web

静态类型,除了保证了类型安全。更重要的是,让你的电脑、软件可以更懂你的代码涵义。从而使得制作更好的生产力工具成为可能。生产力工具的提升,让开发者可以更加愉悦的写代码。从而最终提高生产力。

常用功能

6Rn2iaA.jpg!web

此处主要通过demo展示带TS在VS Code中一些能力。代码提示、引用查询、自动import、代码即文档等。

生产力提高的背后

工具能力的提升只是在表面。相信很多人会有这样的疑问:没错在VS Code里写TS很方便。但是这种不都是IDE本身提供的吗?

iUNzyeF.jpg!web

事实上,这些能力其实是由TS本身提供的:

1、与其他编译器不同,TS的编译器不是一个黑盒,而是完全对外开放的。

2、TS的编译器架构,包括了底层了核心Ts编译器,语言服务,并且通过ts server把他所支持的功能都通过api暴露出来。

3、第三方的工具就可以通过这个api来直接使用ts语言服务的各种功能。

4、通过这种方式,其他的ide,工具,也可以快速的集成TS的相关能力。这也是为什么即使你使用webStorm也可以获得与VS Code类似的TS开发体验。

理由三:端到端的类型安全

使用TS之前

ZbIRrqB.jpg!web

图中是一个比较常见的架构。我们有运行在浏览器中的页面代码,它与中间的接入层nodejs服务进行通信,在后台我们还有一个C++服务,它nodejs服务之间用protobuf, 以rpc的形式来进行通信。

这个时候,一旦后台的协议发生更改,是一件非常棘手的事情,因为这里面没有任何类型追踪,我们需要在前端浏览器代码和nodejs代码中全局搜索对应的字段来修改,非常容易改错改漏。

# 使用TS之后

qeamumv.jpg!web

通过protobuf的TS插件,将请求、返回结构,方法等全都转换为TS。并且在页面代码与node服务代码中进行共享。

eeeyaer.jpg!web

当proto协议文件发生更改的时候,只需要重新生成新的TS类型文件,无论是页面代码,还是node服务代码都会自动报错,提示开发者去做对应字段的修改。

理由四:强大的社区支持

第三方库

RFzqUrr.jpg!web

因为现如今任何一个前端项目都会引入大量的第三方库。对于这些第三方库,如果作者本身没有提供类型定义怎么办呢?

社区早就有了非常成熟解决方案,DenitelyTyped这个仓库目前是github排名第八的项目,有着超过10000名的代码贡献者,这里面有超过5000个前端库的类型定义。基本上你会用的,都已提供了类型定义。

框架反哺

qUbi63V.jpg!web

我们也发现越来越多的,非常有影响力的前端框架的新版本都开始用ts来进行重写了。Angular 2, Vue3等等。

而这些社区中的开发者,都是开源社区最活跃的参与者,他们会将开发过程中遇到的ts的一些问题,通过PR或者反馈的方式再反哺到ts社区中,让ts的生态越来越好。

团队TS引入策略

确定是否有必要引入

A7vqiyI.jpg!web

在正式引入之前,第一点还是需要明确一下,你的团队的具体需求。

1、你的项目规模是怎样的?当然规模越大TS的帮助也就越大。

2、项目是由存在多人合作或者经常有新人员加入呢?如果回答是yes,TS的使用,可以让你的代码更规范,让新人更快速的熟悉代码。

3、是否需要长期维护?TS100%可以让你的项目结构更健康,更容易的去重构。

定点试验

nMfiaeF.jpg!web

1、成立实验小组,让这部分人员先行,在项目中进行试点。2、这段时间内,要定期的对这部分人员进行问卷调查,看看他们的满意度。3、将遇到的疑问,譬如像第三方依赖怎么办之类的问题,梳理成FAQ,以便后续做更大范围的宣导。

构建迁移

r6ZNVbq.jpg!web

构建迁移,其实非常的简单。通常我们需要处理的就是babel和webpack。这两者现在都利用了TS 的语言服务能力。

1、如果你的代码需要用babel转换,你可以直接加上babel-ts插件,这样你编译出来的代码就自动会去除掉ts的类型,其他的功能还是走babel的转化逻辑。

2、更多的时候,你会选择第二种,直接放弃掉babel,使用webpack的ts-loader直接对ts进行编译。

构建优化

R7z6jqF.jpg!web

TS3.0增加了project reference功能。

1、你只需要在子文件夹里面,分别建一个新的tsconfg文件。在要引用的tsconfig中加上reference引用到另一个项目。在被引用的文件夹的tsconfig中增加composite为true。

2、通过这样的配置,当ts在做类型检查的时候,只会检查当面项目的ts文件。保证了检查过程的高效。

3、当你运行tsc build的时候,它也会进行增量的构建,只有当引用文件发生修改过期的时候,才会重新构建。

Lint迁移

3im2Izf.jpg!web

1、首先在你eslintrc.js文件中引入TS的parser与plugin。2、Extends里面,建议就使用typescirpt-eslint这个包推荐的几种配置。3、接下来把你团队原来的eslint规则包引入进来,基本上你会发现原来所有eslint规则都是可以正常工作的。你也可以继续使用rules属性来覆盖继承的规则。

依赖迁移

FBfUVvU.jpg!web

1、对于那些本身已经用TS来写的依赖,你不需要做任何改变。正常import进来就可以了。但是如果库本身没有自带类型,那你就需要使用denitelyTyped这个库,来把类型当作dev依赖装上就可以了。2、然而如果DT里面也找不到类型定义。那你需要做的就是,在d.ts里面declare一下这个module,可以自己给它添加类型定义,最终发布到DT上。3、更棘手的情况是类型找到了,但是有错。导致明明我传出正确的参数,还是会看到恼人红线,这里有两种做法:1. 依赖类型声明本身的写法,你可以在import 类型后,通过extends或者merge的能力对源类型进行扩展。2. 修改类型错误,给DT提PR。

代码迁移:混合模式

7b6vYzV.jpg!web

TS的迁移有两种方式,一种是混合模式,也就是说,把allowJs开关打开,然后一个个的把.js改为.ts,再修复类型。

代码迁移:激进模式

FbiANjE.jpg!web

一次性的把所有js后缀全部改成ts。遇到比较难写的类型,或者文件过大的时候。你可以分别使用@ts-ignore或者@ts-nocheck(TS3.7)来忽略掉下一行的类型检查,或者整个文件的类型检查。

总结

TypeScript之所以取得成功,有一个很重要的原因就是他的定位明确:让JavaScript变得更好,而非取代。

很多没有真正使用过TS的人,对TS的印象往往还停留在“静态类型的JS”。而忽略了“提高生产力”才是TS目前的核心设计目标。

56%的npm开发者都在使用TS,惊人的数字背后是确凿的事实。

所以你还在等什么呢?

YZzamaU.jpg!web

轻点在看,支持作者


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK