什么是TypeScript
TypedJavaScriptatAnyScale.
添加了类型系统的JavaScript,适用于任何规模的项目。
以上描述是官网[1]对于TypeScript的定义。
它强调了TypeScript的两个最重要的特性——类型系统、适用于任何规模。
TypeScript的特性§
类型系统§
从TypeScript的名字就可以看出来,「类型」是其最核心的特性。
我们知道,JavaScript是一门非常灵活的编程语言:
它没有类型约束,一个变量可能初始化时是字符串,过一会儿又被赋值为数字。
由于隐式类型转换的存在,有的变量的类型很难在运行前就确定。
基于原型的面向对象编程,使得原型上的属性或方法可以在运行时被修改。
函数是JavaScript中的一等公民[2],可以赋值给变量,也可以当作参数或返回值。
这种灵活性就像一把双刃剑,一方面使得JavaScript蓬勃发展,无所不能,从2013年开始就一直蝉联最普遍使用的编程语言排行榜冠军[3];另一方面也使得它的代码质量参差不齐,维护成本高,运行时错误多。
而TypeScript的类型系统,在很大程度上弥补了JavaScript的缺点。
TypeScript是静态类型§
类型系统按照「类型检查的时机」来分类,可以分为动态类型和静态类型。
动态类型是指在运行时才会进行类型检查,这种语言的类型错误往往会导致运行时错误。JavaScript是一门解释型语言[4],没有编译阶段,所以它是动态类型,以下这段代码在运行时才会报错:
letfoo=1;
foo.split('');
//UncaughtTypeError:foo.splitisnotafunction
//运行时会报错(foo.split不是一个函数),造成线上bug
静态类型是指编译阶段就能确定每个变量的类型,这种语言的类型错误往往会导致语法错误。TypeScript在运行前需要先编译为JavaScript,而在编译阶段就会进行类型检查,所以TypeScript是静态类型,这段TypeScript代码在编译阶段就会报错了:
letfoo=1;
foo.split('');
//Property'split'doesnotexistontype'number'.
//编译时会报错(数字没有split方法),无法通过编译
你可能会奇怪,这段TypeScript代码看上去和JavaScript没有什么区别呀。
没错!大部分JavaScript代码都只需要经过少量的修改(或者完全不用修改)就变成TypeScript代码,这得益于TypeScript强大的[类型推论][],即使不去手动声明变量foo的类型,也能在变量初始化时自动推论出它是一个number类型。
完整的TypeScript代码是这样的:
letfoo:number=1;
foo.split('');
//Property'split'doesnotexistontype'number'.
//编译时会报错(数字没有split方法),无法通过编译
TypeScript是弱类型§
类型系统按照「是否允许隐式类型转换」来分类,可以分为强类型和弱类型。
以下这段代码不管是在JavaScript中还是在TypeScript中都是可以正常运行的,运行时数字1会被隐式类型转换为字符串'1',加号+被识别为字符串拼接,所以打印出结果是字符串'11'。
console.log(1+'1');
//打印出字符串'11'
TypeScript是完全兼容JavaScript的,它不会修改JavaScript运行时的特性,所以它们都是弱类型。
作为对比,Python是强类型,以下代码会在运行时报错:
print(1+'1')
#TypeError:unsupportedoperandtype(s)for+:'int'and'str'
若要修复该错误,需要进行强制类型转换:
print(str(1)+'1')
#打印出字符串'11'
强/弱是相对的,Python在处理整型和浮点型相加时,会将整型隐式转换为浮点型,但是这并不影响Python是强类型的结论,因为大部分情况下Python并不会进行隐式类型转换。相比而言,JavaScript和TypeScript中不管加号两侧是什么类型,都可以通过隐式类型转换计算出一个结果——而不是报错——所以JavaScript和TypeScript都是弱类型。
虽然TypeScript不限制加号两侧的类型,但是我们可以借助TypeScript提供的类型系统,以及ESLint提供的代码检查功能,来限制加号两侧必须同为数字或同为字符串[5]。这在一定程度上使得TypeScript向「强类型」更近一步了——当然,这种限制是可选的。
这样的类型系统体现了TypeScript的核心设计理念[6]:在完整保留JavaScript运行时行为的基础上,通过引入静态类型系统来提高代码的可维护性,减少可能出现的bug。
适用于任何规模§
TypeScript非常适用于大型项目——这是显而易见的,类型系统可以为大型项目带来更高的可维护性,以及更少的bug。
在中小型项目中推行TypeScript的最大障碍就是认为使用TypeScript需要写额外的代码,降低开发效率。但事实上,由于有[类型推论][],大部分类型都不需要手动声明了。相反,TypeScript增强了编辑器(IDE)的功能,包括代码补全、接口提示、跳转到定义、代码重构等,这在很大程度上提高了开发效率。而且TypeScript有近百个[编译选项][],如果你认为类型检查过于严格,那么可以通过修改编译选项来降低类型检查的标准。
TypeScript还可以和JavaScript共存。这意味着如果你有一个使用JavaScript开发的旧项目,又想使用TypeScript的特性,那么你不需要急着把整个项目都迁移到TypeScript,你可以使用TypeScript编写新文件,然后在后续更迭中逐步迁移旧文件。如果一些JavaScript文件的迁移成本太高,TypeScript也提供了一个方案,可以让你在不修改JavaScript文件的前提下,编写一个[类型声明文件][],实现旧项目的渐进式迁移。
事实上,就算你从来没学习过TypeScript,你也可能已经在不知不觉中使用到了TypeScript——在VSCode编辑器中编写JavaScript时,代码补全和接口提示等功能就是通过TypeScriptLanguageService实现的[7]:
what-is-typescript-vscode
一些第三方库原生支持了TypeScript,在使用时就能获得代码补全了,比如Vue3.0[8]:
what-is-typescript-vue
有一些第三方库原生不支持TypeScript,但是可以通过安装社区维护的类型声明库[9](比如通过运行npminstall--save-dev@types/react来安装React的类型声明库)来获得代码补全能力——不管是在JavaScript项目中还是在TypeScript中项目中都是支持的:
what-is-typescript-react
由此可见,TypeScript的发展已经深入到前端社区的方方面面了,任何规模的项目都或多或少得到了TypeScript的支持。
与标准同步发展§
TypeScript的另一个重要的特性就是坚持与ECMAScript标准[10]同步发展。
ECMAScript是JavaScript核心语法的标准,自2015年起,每年都会发布一个新版本,包含一些新的语法。
一个新的语法从提案到变成正式标准,需要经历以下几个阶段:
Stage0:展示阶段,仅仅是提出了讨论、想法,尚未正式提案。
Stage1:征求意见阶段,提供抽象的API描述,讨论可行性,关键算法等。
Stage2:草案阶段,使用正式的规范语言精确描述其语法和语义。
Stage3:候选人阶段,语法的设计工作已完成,需要浏览器、Node.js等环境支持,搜集用户的反馈。
Stage4:定案阶段,已准备好将其添加到正式的ECMAScript标准中。
一个语法进入到Stage3阶段后,TypeScript就会实现它。一方面,让我们可以尽早的使用到最新的语法,帮助它进入到下一个阶段;另一方面,处于Stage3阶段的语法已经比较稳定了,基本不会有语法的变更,这使得我们能够放心的使用它。
除了实现ECMAScript标准之外,TypeScript团队也推进了诸多语法提案,比如可选链操作符(?.)[11]、空值合并操作符(??)[12]、Throw表达式[13]、正则匹配索引[14]等。
总结§
什么是TypeScript?
TypeScript是添加了类型系统的JavaScript,适用于任何规模的项目。
TypeScript是一门静态类型、弱类型的语言。
TypeScript是完全兼容JavaScript的,它不会修改JavaScript运行时的特性。
TypeScript可以编译为JavaScript,然后运行在浏览器、Node.js等任何能运行JavaScript的环境中。
TypeScript拥有很多编译选项,类型检查的严格程度由你决定。
TypeScript可以和JavaScript共存,这意味着JavaScript项目能够渐进式的迁移到TypeScript。
TypeScript增强了编辑器(IDE)的功能,提供了代码补全、接口提示、跳转到定义、代码重构等能力。
TypeScript拥有活跃的社区,大多数常用的第三方库都提供了类型声明。
TypeScript与标准同步发展,符合最新的ECMAScript标准(stage3)。
附:TypeScript的发展历史§
2012-10:微软发布了TypeScript第一个版本(0.8),此前已经在微软内部开发了两年。
2014-04:TypeScript发布了1.0版本。
2014-10:Angular发布了2.0版本,它是一个基于TypeScript开发的前端框架。
2015-01:ts-loader发布,webpack可以编译TypeScript文件了。
2015-04:微软发布了VisualStudioCode,它内置了对TypeScript语言的支持,它自身也是用TypeScript开发的。
2016-05:@types/react发布,TypeScript可以开发React应用了。
2016-05:@types/node发布,TypeScript可以开发Node.js应用了。
2016-09:TypeScript发布了2.0版本。
2018-06:TypeScript发布了3.0版本。
2019-02:TypeScript宣布由官方团队来维护typescript-eslint,以支持在TypeScript文件中运行ESLint检查。
2020-05:Deno发布了1.0版本,它是一个JavaScript和TypeScript运行时。
2020-08:TypeScript发布了4.0版本。
2020-09:Vue发布了3.0版本,官方支持TypeScript。