程序员眼里的索引号从0开始,所以此处称为第0部分:
0.1 TypeScript是什么?
先总体介绍一下TypeScript,它是一门开源的强类型语言,是JavaScript的超集,核心维护团队是微软。
TypeScript可以被编译成可读性良好的JavaScript,且没有运行时,就是说编译之后的TypeScript类型信息会消失,变成了普通的JavaScript代码。我们可以把TypeScript当成一门静态语言分析工具,我们在写TypeScript代码过程,TypeScript会进行很多检查,确保类型安全。浏览器或者node只认识JavaScript,他们并不知道TypeScript的存在,实际运行的只是JavaScript代码。
TypeScript中包含有三个部分:
1)语言本身(Language)
2)语言服务器(Language Server):负责为IDE的文本编辑器提供大量的自动完成列表、鼠标hover到各种元素时提示的tooltip,相当于是可以用来查询TypeScript代码当前各种信息
3)编译器(Compiler):为语言服务器服务,执行类型检查、TypeScript代码的解析和编译、Symbol信息的读取等,可以接收TypeScript文件,编译输出JavaScript文件
设想我们在做JavaScript项目向TypeScript迁移,迁移过程项目中就会同时存在JavaScript代码和TypeScript代码,所幸Babel到了7之后对TypeScript的支持就非常好,简单配置就可以将TypeScript代码和较高ECMA版本的JavaScript代码编译成指定目标运行环境的JavaScript代码,在兼顾项目工程性的同时,不用担心代码编译后运行环境。Babel7可以让我们不用担心TypeScript的加入,就跟之前写JavaScript时可以直接使用较新的ES特性不用担心是运行在IE上。我们编写TypeScript也同样可以如此,我们可以使用最新的TypeScript语法,编写更为现代的TypeScript代码,不用担心代码所运行的浏览器环境。
可以按照官方示例一步步配置webpack + babel 7 + TypeScript 的工程环境:
或者通过这个命令行直接下载我为大家准备好的项目,并编写好了demo:
git clone gitee.com/wu0792/lear… && cd ./learn-ts && git checkout ch01-introduction && code .
我们来看下近几年TypeScript的下载量的变化趋势:
www.npmtrends.com/typescript-…
TypeScript下载量在最近两年左右上涨超500%,上升速度犹如坐上火箭。而且跟react的上升趋势有很大相像之处(或许是因为微软的大力推广,大量react开发者都选择使用TypeScript开发):
\
0.2 类型信息有什么用?
为什么我们要为JavaScript添加类型信息?为什么微软费心费力去做TypeScript这个项目呢?
JavaScript是一门弱类型语言,开发者在使用时有很大的自由度,但凡事都有双面性:过大的自由度会引入运行时风险,比如函数调用时的错误类型传参、访问不存在的成员、重构函数增加参数的风险等等,这些问题在编写代码时不会暴露,只有在运行时才会被发现,发生时可能已经影响到了用户使用我们的软件。
为了解决上面这些问题,TypeScript增加了类型信息:
首先,它给了我们机会对我们要写的代码做出更多的假定和约束,这些假定和约束成为了我们代码的一部分。所以如果我们有个函数是以字符串作为参数,我们就可以明确指出这个参数要求字符串类型。当我们看一段常规的JavaScript代码,我们只是去写一段注释描述这个信息,但其他人是否看这个注释、是否遵守这个注释要求都是不确定的。你还可以在方法内部增加断言去动态验证参数类型是否是字符串,不符合时就抛出异常,但这就把代码引向了防御类型编程:你不相信任何输入。这会带来很多额外成本,包括运行时的性能成本和代码可读性的成本。新同事学习这些代码,要先分辨出来哪些代码是类型断言哪些是函数的实际功能,这增加了代码的维护和阅读成本;
其次,在访问对象成员时,出现拼写错误就会让我们访问不存在的对象成员,我每天都会犯几次拼写错误,这是非常正常的。而类型信息可以帮助我们对属性和方法访问进行校验,会确保我们的输入准确性,不会再因为拼写错误导致访问成员出现undefined异常;
第三:关于重构的例子:假设我们编写的一个方法在四个地方被调用到,我们现在为这个方法新添加另外一个不为空的参数,修改三处调用后,第四处调用却没有修改,类型检查的编译器会提示第四处调用的参数不匹配,这种有用的校验错误在JavaScript是很难直接被检测到的。
最后,我们会看到TypeScript对开发体验的提升有很大帮助,我以前使用c#这门强类型语言做过后端开发,使用Visual Stuido作为IDE,它可以得到很多的提示信息:包括这个标识符是class名称,另外一个是clas的public或者private类型成员,并且可以得到非常有用的auto complete功能,明确知道哪些是可以被访问的成员哪些不能…这些IDE功能在动态语言比如JavaScript中就很难完美做到。
综上:我们已经明白,我们正在将大量的错误暴露的时间点从运行时提前到了编译时,我们得到了更为早期及时的反馈,而这些静态分析是只要根据源代码就即时得出反馈信息,和运行到具体那行代码才暴露出来错误相比有非常大的提升,后者发现问题时已经影响到软件运行,可能已经导致线上事故。当然,我们可以通过测试用例去提前排查这些可能发生的错误,但功能上线时,用例是否已经写完了,覆盖率是否完整,新编写的功能是否会影响到旧的用例等等这些问题在我们写代码的时候是长期存在的:没有完美的测试用例,这就意味着我们不能完全依赖测试用例来避免类型错误。
0.3 大纲
如下是我们将要学习的大纲:
第一部分,我们会学习一个简单的TypeScript的demo,我们没时间去讨论TypeScript的每个细枝末节,demo的学习目的是能够给大家一个关于如何使用TypeScript的完整的心智模型,学完之后我们就一只脚踏入了TypeScript大门,可自行去学习的功能。
第二部分,我们将要学习的如何配置TypeScript的compiler,这非常重要,因为可以让你的代码压缩70%,如果你要为IE6进行编译,就有大量的额外代码,并且会帮助大家设置类型检查的严格等级,如果你真的想要类型安全,就要把检查规则设置得足够完善。
第三部分,我们将会介绍如何将一个JavaScript项目迁移到TypeScript,实现这个转换有很多糟糕的方法,方法不当会有很多风险和困难。我们会通过三个步骤实现迁移,这个迁移变得非常流畅和递增的过程,不必是很大破坏性。
第四部分,我们将会花较多时间在高级类型和泛型上面,只接触过JavaScript的同学可以没听过泛型,你可以把泛型理解成参数化类型,我们传一个值给函数,函数将对这个值进行参数化,就像是一个填空的场景,这是一个非常强大的类型声明方式,让类型的使用更加灵活高效,但使用不当也会造成不必要的复杂性,这些注意点我们也会讲到;
第五部分,在最后,我将会大家一个demo来讲解TypeScript complier是如何处理我们编写的TypeScript,不是因为我觉得大家工作中会使用到这些,而是通过理解TypeScript complier处理TypeScript代码的过程,揭开面纱去了解TypeScript complier背后的原理,明白complier用什么数据结构的表达方式,这对于理解整个框架结构是非常有用的。