这是一个由 simviso 团队对 JSConf.Hawaii 中关于大规模应用Typescript相关话题进行翻译的文档,内容并不是直译,其中有一些是译者自身的思考。分享者是Brie Bunge,Airbnb高级前端工程师。javascript
视频地址:大规模应用TypeScript「2019 JSConf -Brie Bunge」前端
视频翻译文字版权归 simviso 全部,微信公众号:Simviso,未经受权严禁转载java
本次参与翻译人员react
你们好,个人名字是 Bree,我在 Airbnb 工做。git
在大公司中进行大的改革很难。这须要去说服不少人,同时又须要涉及大量的代码迁移。我想要与你们分享咱们是如何将 TypeScript 应用到 Airbnb这个公司的平常开发中的。我感谢大家能在这里,我知道大家彻底能够披着时髦的毛巾在海边娱乐。程序员
我设想这里的每一个人都会有这样一些问题, 你要为你的公司进行重大的变革, 同时这可能会被做为一个案例进行研究, 你如今是否在公司内部积极的推进将项目开发迁移到 TypeScript,为此我将提供一些技术和工具上的帮助。github
或许,你已经听过一些 TypeScript 的内容,而且想了解更多。typescript
首先,咱们会介绍 TypeScript 是什么?规模化又意味着什么? 对于将Typescript规模化的过程又有什么建议? 基于这些问题和疑问,我会给出相应的解答, 咱们该经过什么样的迁移策略将 JavaScript 逐步迁移到 TypeScript。编程
请你们快速举手示意一下以方便我知道大概有多少人以前使用过 TypeScript, cool,有这么多人。 还有一部分人没有举手, 那么,让咱们快速介绍一下, 这样每一个人都在同一块儿跑线上了。后端
假如咱们有这么一个 greeter 方法, 它接收一个name
参数,而后返回 "hello" + name。 So,若是咱们传入的是"JSConf"
,它会和睦的说"hello JSConf"
。
可是在这种状况下,若是咱们传递的参数类型不是字符串,而是一个字符串数组,那么 TypeScript, 就会给咱们一个错误。即这是一个字符串数组,函数接收的参数类型是 string,不支持该分配。
咱们不须要再经过点击刷新页面这一流程来从咱们的控制台中查看错误并肯定该错误所发生的位置。 能够看到,在咱们输入后,当即就从编辑器中获得了这个错误。
person
对象。同时,你能够定义更复杂的构造类型。 Typescript一般带有一个编译器, 当出现问题时就能够立马告诉你。 它还有一个能够与编辑器挂钩的语言服务器,能够帮咱们进行自动编译,提供重构相关提示等等
神奇吧!我不必来回浏览文档页面,我在编辑器中就能够获得这些全部。 经过在咱们的代码中使用类型,咱们能够作更多的事情。
咱们只是稍微接触了下TypeScript的类型限制,可是能够经过这个来帮你捕获这种类型的错误,以及支持它的工具。
关于TypeScript的类型检查内容就到此,那关于规模化应用这一部分呢?
若是你一时疏忽,输入了一个错误的变量,那你将会获得这样的一个错误提示,so,在 TypeScript 中真的会发生这样的事。 因此,让咱们来修复下。
但当团队规模达到数百位工程师,同时代码量也愈来愈多,那么交流方式就要发生改变。 咱们须要进行一些改变,即当咱们想要在咱们的主仓库中使用TypeScript的时候(这里指Powers | airbnb.com的主仓库), 同时让TypeScript成为前端主要开发语言。 这个改变影响的人越多,那么必须迁移的代码也就越多,那咱们用数字来讲明规模化意味着什么。
这真的有不少代码,我甚至能看到一些Backbone
的代码。能够想一下JavaScript走过了多少年,它在Airbnb这里也走过了十多年。因此咱们有大量的开发人员在维护这些代码,
目前公司有超过1300名开发人员,其中有200个是前端, 这些前端工程师大多数都参与了主仓库的贡献。
这些数字给咱们展示了当时咱们提议要使用TypeScript时所面临的大环境。 那么在这种规模下,咱们当时是一个什么样子呢?
你们会权衡这些提议的利弊, 咱们会站在团队的角度去决定向前迈出这步是否有意义。 这确保了咱们能够做为一个集思广益的团队,对所作的事情作出深思熟虑的决定,这样能够避免在没有正当技术理由的状况下就“上车”。
从2016年起,Airbnb 已经在一些小规模团队中探索使用 TypeScript。在2017年的前端调查中,静态类型系统呼声最高。 基于这个信号,Joe(第二排那个Joe)和我起草了一个关于TypeScript的提案,并将它交给前端工做组。 这项提案详细说明了为何在Airbnb使用TypeScript是有意义的。
让我来说讲主要的缘由。 airbnb的使命是要创建一个让每个人都感觉到世界到处都是家(airbnb是一家旅游住宿的公司), 用户对咱们的产品提出的每个建议都能会让咱们向着这个目标更进一步, 对于你正在开发的产品也是如此。
使用TypeScript,工程师能够更安全快速的迁移代码。 在Airbnb咱们引入了GraphQL 和Apollo,它可使咱们经过自定义的GraphQL模板来生成TypeScript类型
这意味着咱们能够获得端到端之间的类型安全, 由于前端和后端所使用的数据类型共享了同一个事实上的定义源, 后端工程师可以在不影响客户端的状况下对API进行修改,而前端工程师则能够确信哪些数据将从服务器返回。
类型不匹配一直是咱们的主要bug所在。 因此,这种端到端的类型安全性是一个主要的卖点。
彷佛须要先将包转换为 TypeScript。 这看起来像是须要首先将这个包转换为TypeScript 但这里有个问题,由于维护人员不容许咱们对它作TS转换操做,可能他们也不情愿这么作。 由于在咱们提案的早期,咱们并不肯定是否要一直按照这个提案走下去。
可是从另外一个层面来说,咱们使用TypeScript是为了可让开发人员能够有更好的体验。 咱们须要TypeScript提供的类型安全性, 那么咱们该如何解决看似鸡和蛋的问题呢?
TypeScript有一个叫作声明文件的功能, 即一个以.d.ts为扩展名的文件,经过它咱们能够为JavaScript文件定义类型。
.d.ts
文件。 方法里没有实现细节, 它只描述了类型。 TypeScript将它们组合到一块儿,这样,在编译是使用这个声明文件,在运行时使用这个原生的JS文件。
因此,让咱们回到最初的场景,看看声明文件是如何提供帮助的。 那么咱们回到咱们刚才提的问题(要不要一开始就转换),看看声明文件是如何提供帮助的。 固然,若是那个项目已转换为 TypeScript,咱们就没有必要再生成一个.d.ts
文件来做为TypeScript构建时的一部分(由于在使用TS编程的时候,要经过它对生成的JS进行调用)。
但咱们认为这不止一种选择。 相反,咱们能够将声明文件放在咱们的 TypeScript 项目中。 另外一个选择则是咱们能够建立一个单独的NPM包,并将全部声明文件放入其中 。 这很棒,由于咱们如今能够跨多个仓库共享这些声明文件。
@types/react
包中针对React的5000个经常使用包作了类型声明, @types/react与其余5000个其余包都在
DefinitelyTyped
这个仓库中,它由社区在维护
在咱们的主仓库中,绝大多数的公共依赖都已经由DefinitelyTyped 作到了类型声明, 有活跃的社区氛围是TypeScript 的一个主要卖点。咱们也回馈了一点力量,我相信在这个房间里也有人作出了贡献,谢谢。 这些公共的NPM包的类型声明已经有DefinitelyTyped
在作了,但那些内部的包该怎么办?
@airbnb-types/*
),这样,你只须要安装
@airbnb-types
便可 仓库的设置相似于类型的明确性。 这个仓库的设置与DefinitelyTyped相似 因此咱们能够在里面添加并发布这些内部类型。 咱们开源了一个starter 工具包,若是你又兴趣的话,能够来参与下。 它里面没有类型定义,它只是在教你如何进行一些配置以便于进行测试或者发布本身的类型定义。
那么 TypeScript 究竟能帮忙避免多少 bugs 呢? 近期,一个叫作“该不应作类型定义”的研究代表,在选择了TypeScript 的 github 仓库中,有 15% 的 bugs 获得了避免。 在咱们内部,有一个记录生产环境事故的流程。
这个流程的本意并非为了责怪谁,而是要从错误中进行学习,这样咱们以后就不会再犯相似的错误。 因此我坐下来读了六个月的总结报告。 阅读这些总结报告颇有意思, 我最喜欢的就是未捕获的异常以及危险的参数计算。 好吧,也许这些错误的名字并无那么使人激动。 不管如何,我将这些错误归类为与 JavaScript 相关或无关,以此肯定哪些错误能够经过使用Typescript 来避免
让咱们一块儿看个例子,使用TypeScript会带来哪些帮助 咱们对所分享的这个 Input 组件进行修改,经过一些设置来还原bug。 用户没法提交表单是由于它再也不能经过验证。
onBlur
prop。 这就致使在好几个不一样仓库中都出现了这同一个问题 这里 Input 组件做为Redux Form的一部分进行使用,指望获得一个事件或值,以便验证正常工做。
38%!
咱们发现有38%的事故致使了生产阶段的bug。 这些对咱们用户产生实际影响的bug,可使用TypeScript来阻止。 这对咱们来讲是个巨大的发现。 它有助于实现影响。 它有助于将这种(积极)效果转换到现实中。 咱们复制了一些BUG事件,并向你们展现了TypeScript所给出的Error提示,而后对bug进行修复(也就是咱们看到的bug提示灯泡灭掉了)
的确,咱们也能够经过写测试代码来捕捉这些,可是经过静态类型检查能够额外增长一层保护层。 所以,若是你所在公司有相似的历史,那么你可能就有必要和懂Typescript小伙伴一块儿来看一下这些问题在大家的代码里所占的比例。
咱们在主仓库启用超过了500条eslint规则,也使用typescript eslint解析器,咱们很高兴地发现它们中的大多数均可以工做。 若是咱们在未来要弃用Typescript的话,咱们能够剥离类型,并最终获得大体相同的JavaScript。
因此咱们逐一记录、思考、跟进,而且针对提出的问题和担心找到解决办法。 与批评者合做并听取他们的担心对咱们来讲很是重要。 最后这些批评者中的大部分转而会支持咱们, 咱们的提案也从他们的反馈中变得更为健壮。
咱们已经解决了早期的矛盾,并改进了工具和文档,因此以后团队成员会更容易入门。
咱们一直与 typescript 团队保持着持续联系, 并帮忙解决一些问题,好比,更好的默认属性优先级处理。
在这个阶段,咱们本身内部的 typescript 社区也获得了发展。 可是大部分 Airbnb 的员工还不知道 typescript, 这也意味着更多的人能够去帮助和回答他们的问题。 接下来咱们将会进入测试状态,团队能够选择使用它。 为了帮助团队,咱们建立了内部文档和风格指南,并举办了一些学习课程。
咱们创建了一个聊天组,一个内部的类Stack Overflow,谷歌Email主题,github组,来供组内成员交流。 咱们想确保人们能获得他们须要的帮助, 最后一步是将 typescript 彻底普及化。 此时就意味着它是稳定状态,每一个人都应该开始使用它, 咱们目前正在努力地去接近这个目标。 剩下的步骤就是巩固风格指南、文档、增强内部培训和迁移更多代码。 到目前为止,咱们大约有50%的团队使用 typescript,在主仓库中,有10%的文件已经被转换成 typescript 经过这种渐进的方法,使团队迁移至 typescript 的过程更加顺畅。 若是从第一天开始就要求每一个人应该使用TypeScript, 那么接下来的每一个人都会遇到一样的问题。 相反,咱们先在小范围内使用 typescript ,而后总结一些经验技巧,当咱们准备把它大规模推广时,这些经验技巧也会用得上。
咱们已经探索出了几种将代码迁移至 typescript 的方式。
在关于迁移的话题上,我想花些时间和你们分享一些咱们认为有用的技巧。
$TSFixMe
, 咱们经过TypeScript的any类型添加了一个全局类型别名,这意味着它能够为任何类型。 咱们将它称之为$TSFixedMe,代表在代码向TypeScript迁移完成后,再来将类型修正 平时最佳实践是避免使用
any
,由于它会形成类型安全丢失,但它在迁移过程当中会颇有帮助。
@ts-ignore
注解能够作到忽略下一行错误。 正确地输入一个文件可能涉及一些深层依赖链解析(相似于复杂对象)。 咱们能够尝试经过首先转换子文件来避免这种状况,但有时这是不可避免的。 所以,$TSFixedMe和@ts-ignore注解可以帮助拆分这些内容,同时则会增长这些检查工做。 这些都是暂时的,咱们计划添加类型覆盖工具,并在后面咱们改进类型时提供帮助
为了不重复两次类型声明,那就须要与这些类型保持同步。 咱们建立了一个Props
类型,经过它将给定的propTypes
和defaultProps
来派生出一个TypeScript类型。
propTypes
和
defaultProps
组合并获得这个最终类型。 若是你好奇它是如何工做的,你能够查看我在gist上分享的
代码片断。
为了经过编译,有些文件须要进行一些TS Fixed, ts就能够推断出剩余部分。
在这个网页下,它有一个能够经过源代码输出对应的AST树的功能,以及在你对代码的改变同时反映到AST树上。 我也在DefinitelyTyped 这个库提交了关于Jscodeshift的pr,这样的话能够来下降你们在使用TypeScript与Codemod的交互门槛,
在将JavaScript代码迁移到typescript时,有这几种模式。
随着时间的推移,你仍然须要慢慢找到类型,但它为你提供了一个工做前提。 咱们将此工具应用于咱们的内部分享的React组件库,如今在咱们的网站上已经频繁地使用。 咱们有内部的类型定义库(DefinitelyTyped),可是由于react分享组件库的快速发展,因此作到与时俱进地更新太难了, 因此,咱们想直接从源码类型出发。因此这是咱们迁移TS的第一个目标。
在大型组织中实施变革多是一项挑战,但强有力的事实依据和相关问题和担心的解决,可使咱们信服。 采用逐步变化的方式有助于减小摩擦并证实其价值。 一条明确的迁移路线能帮助团队更好的转向新的模式,同时好的工具也能促进这个过渡的过程, 我之因此开始这个工做,是由于以前有个产品组对个人工具感到失望。 当我得知公司内部其余人也有这种改变的想法的时候,我便与他们合做并将之进行下去。
感谢你们的倾听,同时感谢AirBnb为这个项目做出贡献的每个人,尤为是台下的Joe和Mohsen。还有对其余一些优秀的Airbnb工程师表示感谢。 我手上也有些TypeScript主题的小便签和一些钥匙链,先到先得,只限前30人哦!
感谢你们的倾听。