业界对于TypeScript已是政治正确的选择了,愈来愈多的前端库/框架均采用TS,例如Ant Design 4.0、Vue 3.0等。同时,TS也提供了更健全的语法能力、静态的代码类型检查、更友好的代码辅助提示等等。前端
早在2019年,Airbnb就已经在JSConf上分享了其要对现有前端项目进行大规模TypeScript迁移转换的计划。可是对于现有项目进行TypeScript转换并非一件轻松,Airbnb总共有超过200万行代码,超过100个内部npm包。react
大规模代码迁移每每是一项很是复杂的工做,Airbnb探索过几个迁移策略:git
混合迁移策略:一个个文件进行迁移,修复类型错误。allowJS配置能够容许JS和TS文件在一个项目中并存。使用混合迁移策略能够不用暂停当前开发,逐步的一个个文件进行迁移。可是,对于研发人员须要更长的适应和迁移时间。github
彻底迁移策略:一次性实现文件彻底迁移。咱们会使用any或者@ts-ignore注释帮助项目编译,随后会补充更加具体的类型申明。typescript
采用彻底迁移策略有不少的好处:npm
项目的一致性:在彻底迁移策略下,项目使用使用TypeScript来编写,所以,开发者并不须要在JS和TS之间进行切换。json
修复类型比修复文件容易:修复一个完整文件很是复杂,由于它可能有不少外部依赖,所以,采用混合迁移的方式,很难保证迁移的进度和状态。前端框架
所以,Airbnb采用了彻底迁移策略。然而,一次性迁移完整项目难度很是大。Airbnb研发了一个转换工具:ts-migrate,在初试转换过程当中,尽量实现类型的自动转换。微信
固然,这个工具并不能保证明现彻底没有错误的转换,可是在实际使用过程当中,对于一个超过50000行代码、1000个文件的项目,从JavaScript转换到TypeScript使用这个工具每每只须要1天!markdown
在Airbnb,React是主要前端框架,因此主要的codemods转换都是基于React概念。ts-migrate也可能能够适用于其余框架或者三方库。
让咱们看下一个JavaScript项目转换到TypeScript所须要的主要步骤。
{
"extends": "../typescript/tsconfig.base.json",
"include": [".", "../typescript/types"]
}
复制代码
下一步是将代码后缀从.js/.jsx转换成.ts/.tsx,自动化实现这步其实很是简单。
第三步是执行codemod,ts-migrate经过plugins方式来组织代码转换的能力。经过AST解析工具,咱们将原有的JS代码,进行解析,分析类型,添加声明,而后生成相应的TS代码。
ts-migrate有三个部分组成,而且开源在github.com/airbnb/ts-m…
转换工具并不能将一个项目彻底迁移完成,可是,它会经过ignore的注释让编译器忽略错误,从而可让项目尽量运行起来,随后你能够再逐步修复错误问题。
迁移的总体过程以下:
plugin都会放在ts-migrate-plugins目录下面,咱们能够先看下两个插件:explicitAnyPlugin和declareMissingClassPropertiesPlugin。
exlicitAnyPlugin主要会对全部文件中的语义诊断错误进行处理。对于没法推导类型的变量添加any,能够帮助解决编译问题。
迁移前:
const fn2 = function(p3, p4) {}
const var1 = [];
复制代码
迁移后:
const fn2 = function(p3: any, p4: any) {}
const var1: any = [];
复制代码
declareMissingClassPropertiesPlugin一样也会找到类申明中缺失的类型,而且添加any修饰。
reactPropsPlugin能够将PropTypes的类型信息转换成TypeScript的props类型申明。这个插件会在.tsx文件中执行,reactPropsPlugin会寻找全部PropTypes的定义,经过AST进行解析,而且将其转换成一个新的props申明:type Props = {...}。
React中的state和生命周期很是常见,咱们经过两个插件来处理。
若是一个组件是有状态的,reactClassStatePlugin会生成一个新的语句: type State = any; reactClassLifecycleMethodsPlugin会给生命周期方法提供相应的类型申明。
整个工具依旧有很大的改进空间,可是,能够做为TypeScript的初始工具,很好的帮你开始整个迁移过程。这个工具并不支持hooks,由于Airbnb原始项目使用的是老版本的React。
咱们的目标是但愿将项目进行基本类型转换,同时不改变任何代码行为。
经过工具转换可能会致使代码lint检查失败,所以,可使用Prettier进行代码自动格式化,经过ESLint确保代码符合规范。
迁移过程的最后一步是保证全部TypeScript的编译错误能够发现而且修复。咱们会在这些地方插入@ts-ignore而且提供备注。
// @ts-ignore ts-migrate(7053) FIXME: No index signature with a parameter of type 'string...
const { field1, field2, field3 } = DATA[prop];
// @ts-ignore ts-migrate(2532) FIXME: Object is possibly 'undefined'.
const field2 = object.some_property;
复制代码
工具也会支持JSX语法
{*
// @ts-ignore ts-migrate(2339) FIXME: Property 'NORMAL' does not exist on type 'typeof W... */}
<Text weight={WEIGHT.NORMAL}>
some text
</Text>
<input
id="input"
// @ts-ignore ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.
name={getName()}
/>
复制代码
有了这些注释和提示,能够很方便研发人员进行修改。这些注释,也可以帮助咱们了解代码的质量,而且发现潜在的代码问题。
Airbnb的TypeScript代码转换还在进行中,咱们依旧还有一些老旧代码项目使用JavaScript,咱们也有很多$TSFixMe和@ts-ignore注释须要修复。
使用ts-migrate工具极大的提高了咱们的迁移效率。研发人员更加关注于类型的修复。目前,咱们已经转换了~86%的代码,到年末咱们预期会达到95%。
-End-
关注**『奶爸码农』**微信公众号,从事互联网研发工做10+年,经历IBM、SAP、陆金所、携程等国内外IT公司,目前在美团负责餐饮相关大前端技术团队,按期分享关于大前端技术、投资理财、我的成长的思考与总结。