在看这篇文章之前,我是强烈推荐TypeScript 入门教程这本书的。因为这本书它是:从 JavaScript 程序员的角度总结思考,循序渐进的理解TypeScript。文章来源也是该书,但听我一句话:踩过坑才代表会了。【建议收藏】
希望你看这本书之前已经具备了以下技能:
熟练使用JavaScript开发日常项目
已经听说过TypeScript
一、什么是TypeScript?
1、TypeScript词解
Typed JavaScript at Any Scale。
添加了类型系统的 JavaScript,适用于任何规模的项目。
以上是官网[1]对于 TypeScript 的定义。强调了两个重要特性:
- 类型系统
- 适用于任何规模
2、TypeScript的特性
1、类型系统
从 TypeScript 的名字就可以看出来,「类型」是其最核心的特性。
为什么要给JavaScript加上类型呢?
我们知道,JavaScript 是一种轻量级的解释性脚本语言。也是弱类型、动态类型语言,允许隐式转换,只有运行时才能确定变量的类型。正是因为在运行时才能确定变量的类型,JavaScript代码很多错误在运行时才能发现。TypeScript在JavaScript的基础上,包装了类型机制,使其变身成为静态类型语言。在 TypeScript 中,不仅可以轻易复用 JavaScript 的代码、最新特性,还能使用可选的静态类型进行检查报错,使得编写的代码更健壮、更易于维护。
下面是 JavaScript 项目中最常见的十大错误,如果使用 TypeScript,那么在编写阶段就可以发现并解决很多 JavaScript 错误了:
类型系统能够提高代码的质量和可维护性,经过不断的实践,以下两点尤其需要注意:
类型有利于代码的重构,它有利于编译器在编译时而不是运行时捕获错误;
类型是出色的文档形式之一,函数签名是一个定理,而函数体是具体的实现。
TypeScript 是静态类型
类型系统按照「类型检查的时机」来分类,可以分为动态类型和静态类型。
动态类型是指在运行时才会进行类型检查,这种语言的类型错误往往会导致运行时错误。JavaScript 是一门解释型语言,没有编译阶段,所以它是动态类型,以下这段代码在运行时才会报错:
let zhifeiji = 110; zhifeiji.split(' '); // Uncaught TypeError: zhifeiji.split is not a function // 运行时会报错(zhifeiji.split 不是一个函数),造成线上 bug
静态类型是指编译阶段就能确定每个变量的类型(编译时类型检查),这种语言的类型错误往往会导致语法错误。TypeScript 在运行前需要先编译为 JavaScript,而在编译阶段就会进行类型检查,所以 TypeScript 是静态类型,这段 TypeScript 代码在编译阶段就会报错了:
let zhifeiji = 1; zhifeiji.split(' '); // Property 'split' does not exist on type 'number'. // 编译时会报错(数字没有 split 方法),无法通过编译
这段 TypeScript 代码貌似和 JavaScript 没有什么区别。
实际上因为 TypeScript 强大的「类型推论」能力使得大部分 JavaScript 代码都只需要经过少量的修改(或者完全不用修改)就能变成 TypeScript 代码,即使不声明变量 zhifeiji 的类型,也能在变量初始化时自动推论出它是一个 number 类型。如上图没有声明为number却报错了number,足够证明了类型推论。
完整的 TypeScript 代码是这样的:
let zhifeiji : number = 1; zhifeiji.split(' '); // Property 'split' does not exist on type 'number'. // 编译时会报错(数字没有 split 方法),无法通过编译
TypeScript 是弱类型
类型系统按照「是否允许隐式类型转换」来分类,可以分为强类型和弱类型。
以下这段代码不管是在 JavaScript 中还是在 TypeScript 中都是可以正常运行的,运行时数字 1 会被隐式类型转换为字符串 '1',加号 + 被识别为字符串拼接,所以打印出结果是字符串 '11'。
console.log(1 + '1'); // 打印出字符串 '11'
TypeScript 是完全兼容 JavaScript 的,它不会修改 JavaScript 运行时的特性,所以它们都是弱类型。
作为对比,Python 是强类型,以下代码会在运行时报错:
print(1 + '1') # TypeError: unsupported operand type(s) for +: 'int' and 'str'
若要修复该错误,需要进行强制类型转换:
1. print(str(1) + '1') 2. # 打印出字符串 '11
JavaScript 和 TypeScript 中不管加号两侧是什么类型,都可以通过隐式类型转换计算出一个结果——而不是报错——所以 JavaScript 和 TypeScript 都是弱类型。
虽然TypeScript是弱类型,但我们可以通过TypeScript提供的类型系统,以及ESLint提供的代码检查功能。使得TypeScript更像是一个「强类型」。
这样的类型系统体现了 TypeScript 的核心设计理念:在完整保留 JavaScript 运行时行为的基础上,通过引入静态类型系统来提高代码的可维护性,减少可能出现的 bug。
2、适用于任何规模
TypeScript 非常适用于大型项目,类型系统可以为大型项目带来更高的可维护性,以及更少的 bug。
在中小型项目中由于有[类型推论],大部分类型都不需要手动声明了,所以不会很大程度的降低开发效率,故部分中小企业也会选择它。
TypeScript 还可以和 JavaScript 共存。如果你是老的JavaScript项目,你想改造成TypeScript的项目,但又代码量太大并且项目要继续更新。那么你可以新的内容和文件用TypeScript,老的不变。当闲下来时,可以逐步将老的一个一个文件的升级为TypeScript。
事实上,就算你从来没学习过 TypeScript,你也可能已经在不知不觉中使用到了 TypeScript——在 VSCode 编辑器中编写 JavaScript 时,代码补全和接口提示等功能就是通过 TypeScript Language Service 实现的:
一些第三方库原生支持了 TypeScript,在使用时就能获得代码补全了,比如 Vue 3.0[8]:
有一些第三方库原生不支持 TypeScript,但是可以通过安装社区维护的类型声明库[9](比如通过运行 npm install --save-dev @types/react 来安装 React 的类型声明库)来获得代码补全能力——不管是在 JavaScript 项目中还是在 TypeScript 中项目中都是支持的:
由此可见,TypeScript 的发展已经深入到前端社区的方方面面了,任何规模的项目都或多或少得到了 TypeScript 的支持。