迁移到 TypeScript,第 1 部分:简介和入门
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
题图由Franz Harvin Aceituna拍摄,来自Unsplash。
TypeScript (TS)是一门近年来发展迅猛的语言。它在2018 年 JavaScript (JS) 现状调查中取得了令人瞩目的成绩。甚至连Kent C. Dodds这样的知名开发者也开始转向使用 TypeScript。
要了解更多关于 TypeScript 类型系统的工作原理以及它如何帮助你的信息,请观看 TypeScript 的创建者 Anders Hejlsberg 的这段演讲。
对于我们这些已经在使用 TypeScript 的人来说,我们已经无法想象没有它该如何编写 JavaScript 代码了。而随着对 Babel 编译的新增支持,它与 JavaScript 生态系统的其他部分集成起来也变得更加容易。但对于许多想要将应用迁移到 TypeScript 的人来说,这可能会让人感到有些不知所措。当面对一个中大型应用,并且所有代码都已经是用 JavaScript 编写的时候,这种情况会更加难以控制。
市面上很多 TypeScript 学习资料似乎都没有深入探讨如何将一个成熟的应用程序迁移到 TypeScript。更糟糕的是,TypeScript 虽然有自己的官方迁移指南,但它已经严重过时了。
因此,在本系列文章中,我将尝试概述我个人将现有代码库迁移到 TypeScript 的步骤。第一部分将介绍为大规模重写做好准备的步骤,包括设置 TS 编译器以及 TypeScript 编译器的基本要素。
那么,TypeScript究竟是什么呢?
TypeScript 是 JavaScript 的超集,它可以编译成纯 JavaScript 代码。它通过静态类型实现了强大的工具支持和卓越的开发者体验。静态类型带来的 JavaScript 体验提升包括更完善的重构工具、语句自动补全等等。
TypeScript 由 Anders Hejlsberg 编写,他也是 C# 的首席架构师和Turbo Pascal的创建者。TypeScript 2.0 于 2016 年 9 月发布,大幅改进了对 Node.js 模块的支持,并增加了更严格的null检查。此后,该语言不断改进,新增了对象剩余/扩展运算符、--strict模式、条件类型等特性。TypeScript 3.0于 2018 年 7 月发布,甚至通过项目引用支持单体仓库 (monorepo)。
想了解更多关于 TypeScript 的知识,我推荐Basarat 的《TypeScript Deep Dive 》这本书。
TypeScript 入门
首先,我们需要为 TypeScript 设置环境。有两种方法可以实现这一点:
- 使用 Babel 7 + TypeScript 预设进行编译,并让 TypeScript 编译器只进行类型检查。
- 您可以使用 TypeScript 编译器对代码进行类型检查和编译。
由于我们是从 JavaScript 迁移过来的,可以假设我们的开发工具链中已经使用了 Babel,因此可以选择第一种方案。当然,你也可以选择第二种方案,并继续使用 Babel。但如果我们希望更精细地控制所使用的 Babel 预设/插件,那么第一种方案仍然是更好的选择。
初始化编译器
本指南将使用 TypeScript 3.2 版本。它也应该适用于 3.0 及更高版本。
要开始使用 TypeScript,请运行以下命令安装 TypeScript 编译器 CLI:
$ npm install -g typescript
然后运行该命令以使用默认选项tsc --init初始化一个tsconfig.json文件。它会列出所有可用选项及其说明,非必要选项会被注释掉。选项数量可能让你眼花缭乱,但让我们把配置简化到只保留必要选项。
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"esModuleInterop": true,
"downlevelIteration": true,
"lib": ["esnext", "dom"],
"module": "commonjs",
"noUnusedLocals": true,
"outDir": "dist",
"skipLibCheck": true,
"strict": true,
"target": "esnext"
},
"include": ["src"]
}
此设置会将所有内容从指定位置src编译到指定dist文件夹中。这里还有一些其他重要的编译器选项,我们将在下一节中介绍。要进行编译,请运行该tsc命令。
注意:如果您使用 webpack 进行编译,则不需要此outDir选项!
设置构建任务
现在 TypeScript 编译器可以正常工作了,我们可以把它作为脚本包含到我们的package.json文件中!
{
"scripts": {
"build": "tsc"
}
}
这样,您就可以直接运行yarn build(或者npm run build如果您运行的是 npm)来构建您的项目。
配置 TypeScript Babel 预设(可选)
如果您已经使用 Babel 编译 ES6+ JS 代码,则可以使用Babel 的 TS 预设。请注意,您需要Babel 7 或更高版本才能使用此功能。
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread"
]
}
TypeScript 编译器支持所有现代 ES2015 特性以及下一代 ES 特性。但一个常见的问题是,由于TypeScript 不支持,因此无法使用 stage-3 之后的下一代语法。这意味着使用诸如pipeline之类的提议语法会导致类型错误。提议插件应该包含 TypeScript 转译所需的 stage-3 特性。
请注意,Babel 编译器只会移除代码中的类型声明,它不会进行任何额外的类型检查!请务必单独运行类型检查tsc --noEmit。或者更好的是,将其作为编译器选项添加到您的项目中tsconfig.json:
{
"compilerOptions": {
"noEmit": true
}
}
此选项将运行 TypeScript 编译器,但不输出任何代码,因此它只会进行类型检查。您可以将此命令添加tsc到package.json脚本中,如果您也使用持续集成 (CI) 系统,这将很有帮助。
{
"scripts": {
"type-check": "tsc"
}
}
注意:如果您使用 Flowtype,则不能同时使用 Flowtype Babel 预设和 TypeScript 预设。您必须二选一!
tsconfig.json必需品
上面的tsconfig.json文件已经包含了使用 TypeScript 时必不可少的编译器选项。让我们逐一了解这些基本选项。
TS/JS互操作性
TypeScript 编译器还可以配置为对 JS 文件进行类型检查和编译,与 TS 文件并行运行。allowJs它允许编译普通的 JavaScript 文件。如果您也想在 JavaScript 文件中启用类型检查,可以启用 `--typecheck-files` checkJs。如果您是新手,建议先禁用类型checkJs检查,然后手动启用每个文件的类型检查。为此,// @ts-check请在要进行类型检查的 JS 文件顶部添加注释。
另一个值得注意的编译器选项是 `import` esModuleInterop。它允许你使用 CommonJS 模块进行默认导入(例如 `import` import React from 'react';)。对于 TypeScript 老手来说,这个选项类似于 `import` allowSyntheticDefaultImports。唯一的区别在于,它在编译时添加了一些辅助函数,以提高与 Babel 的互操作性。
库和编译目标
有三个选项定义了编译器如何解释你的 TS 代码。
lib概述了编译过程中使用的 TS 库文件。一些常用的库包括:
esnext- 现代 ESnext 功能(最高可达第三阶段推荐)es201x- 年度 ES 规范。请注意,包含某一年将包含其之前的所有年度规范(例如,es2018还将包含es2017、es2016和es2015)。dom- DOM 特定 API。webworker- Web Workers的 API 。
target定义 ES 的目标版本。
module定义 TypeScript 编译器将生成的模块类型。如果设置target为 0es5或更低,则默认为commonjs标准 CommonJS 模块(用于与 Node.js 兼容)。否则,默认为esnextES 模块。
本部分到此结束。在第二部分中,我们将探讨如何通过逐步添加类型来简化 TypeScript 迁移过程。我们还将深入了解 TypeScript 类型系统的特性,以及如何转变编写 TypeScript 应用的思维方式。
我再次强烈推荐Basarat 的《TypeScript Deep Dive》这本书。他的 TypeScript 入门指南对我的学习帮助很大。如果你遇到任何问题,Reactiflux#typescript Discord 服务器的频道里有很多对 TypeScript 了如指掌的热心人士。欢迎随时加入提问!