TypeScript - 介绍
# 什么是 TypeScript
在引入编程社区 20 多年后,JavaScript 现在已成为有史以来应用最广泛的跨平台语言之一。JavaScript 最初是一种用于向网页添加微不足道的交互性的小型脚本语言,现已发展成为各种规模的前端和后端应用程序的首选语言。虽然用 JavaScript 编写的程序的大小、范围和复杂性呈指数级增长,但 JavaScript 语言表达不同代码单元之间关系的能力却没有。结合 JavaScript 相当奇特的运行时语义,语言和程序复杂性之间的这种不匹配使得 JavaScript 开发成为一项难以大规模管理的任务。
程序员编写的最常见的错误类型可以描述为类型错误:在预期不同类型的值的地方使用了某种类型的值。这可能是由于简单的拼写错误、无法理解库的 API 表面、对运行时行为的错误假设或其他错误。TypeScript 的目标是成为 JavaScript 程序的静态类型检查器——换句话说,是一个在代码运行之前运行的工具(静态)并确保程序的类型正确(类型检查)。
TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。
TypeScript 是一种非常受欢迎的 JavaScript 语言扩展。它在现有的 JavaScript 语法之上加入了一层类型层,而这一层即使被删除,也丝毫不会影响运行时的原有表现。许多人认为 TypeScript 「只是一个编译器」,但更好的理解其实是把 TypeScript 看作两个独立的系统:编译器(即处理语法的部分)和语言工具(即处理与编辑器集成的部分)。通过独立看待这两个系统,就可以得到能够解释我们之前所做决策的两个重要视角。
在 npm 上,TypeScript 的下载量每年都在翻倍。截止 2021 年 12 月 1 日,它的每周下载量超过为 2200 万次。而在去年 12 月,这一数字约为 1200 万次。它仍保持着高速增长的趋势,没有任何放缓的迹象。
从 2.0 版本开始,TypeScript 每两月定期发布一个 release。但是现在放缓了发布的节奏,改为每三个月发布一次。其中会花一个月编写新 features 并发布 beta 版本,剩下两个月对 beta 版进行测试和 bug 修复,这使得后续的发布更加稳定。
# JS、ES、TS 的关系
1995 年:JavaScript
当时的网景公司正凭借其 Navigator 浏览器成为 Web 时代开启时最著名的第一代互联网公司。
由于网景公司希望能在静态 HTML 页面上添加一些动态效果,于是 Brendan Eich 在两周之内设计出了 JavaScript 语言。
为什么起名叫 JavaScript?原因是当时 Java 语言非常红火,所以网景公司希望借 Java 的名气来推广,但事实上 JavaScript 除了语法上有点像 Java,其他部分基本上没啥关系。
1997 年:ECMAScript
因为网景开发了 JavaScript,一年后微软又模仿 JavaScript 开发了 JScript,为了让 JavaScript 成为全球标准,几个公司联合 ECMA(European Computer Manufacturers Association:欧洲计算机制造商协会)组织制定了 JavaScript 语言的标准,被称为 ECMAScript 标准。
版本 | 发布时间 | 一般称呼 | 简称 |
---|---|---|---|
第 1 版 | 1997 年 6 月 | ECMAScript 1 | ES1 |
第 2 版 | 1998 年 4 月 | ECMAScript 2 | ES2 |
第 3 版 | 1999 年 12 月 | ECMAScript 3 | ES3 |
第 4 版 | 2007 年 10 月草案 | ECMAScript 4 | ES4 |
第 5 版 | 2009 年 12 月 | ECMAScript 5 | ES5 |
第 6 版 | 2015 年 6 月 | ECMAScript 2015 | ES6 |
第 7 版 | 2016 年 6 月 | ECMAScript 2016 | ES7 |
第 8 版 | 2017 年 6 月 | ECMAScript 2017 | ES8 |
第 9 版 | 2018 年 6 月 | ECMAScript 2018 | ES9 |
第 10 版 | 2019 年 6 月 | ECMAScript 2019 | ES10 |
第 11 版 | 2020 年 6 月 | ECMAScript 2020 | ES11 |
第 12 版 | 2021 年 6 月 | ECMAScript 2021 | ES12 |
2015 年:TypeScript
TypeScript 是 JavaScript 的超集,即包含 JavaScript 的所有元素,能运行 JavaScript 的代码,并扩展了 JavaScript 的语法。相比于 JavaScript ,它还增加了静态类型、类、模块、接口和类型注解方面的功能,更易于大项目的开发。
TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来自 2015 年的 ECMAScript 和未来的提案中的特性,比如异步功能和 Decorators,以帮助建立健壮的组件。下图显示了 TypeScript 与 ES5、ES2015+ 之间的关系:
# TypeScript 与 JavaScript 的区别
TypeScript | JavaScript |
---|---|
JavaScript 的超集用于解决大型项目的代码复杂性 | 一种脚本语言,用于创建动态网页 |
可以在编译期间发现并纠正错误 | 作为一种解释型语言,只能在运行时发现错误 |
强类型,支持静态和动态类型 | 弱类型,没有静态类型选项 |
最终被编译成 JavaScript 代码,使浏览器可以理解 | 可以直接在浏览器中使用 |
支持模块、泛型和接口 | 不支持模块、泛型或接口 |
支持 ES3,ES4,ES5 和 ES6+ 功能 | 不支持编译其他 ES3,ES4,ES5 或 ES6+ 功能 |
社区的支持仍在增长,而且还不是很大 | 大量的社区支持以及大量文档和解决问题的支持 |
# TypeScript 的竞争者有哪些?
TypeScript 的目标是为人们提供编写大型 JavaScript 项目并对后期维护有信心的工具。JavaScript 本身没有的语法支持表示每个标识符的类型,除非运行 JavaScript 并在运行时进行检测。为了解决这个问题,TypeScript 添加了额外的语法。
所以,如果说我们的目标是作为工具提供支持,那么在这个领域有少数几个竞争者是 TypeScript 无法与之竞争的:
- ESLint 和 TSLint:与 TypeScript 的定位相同,它们都是用来突出代码中可能出现的错误,只是没有为检查过程添加新的语法。两者都不打算作为 IDE 集成的工具运行,而且 TS 和 TS/ESLint 经常会说那些对项目没有意义的特性「是对方的领域」。在现代代码中,TS/ESLint 的存在使得 TypeScript 可以做更少的检查,这些检查并不适用于所有代码库。虽然有一些功能重叠了,但可以把它们作为很好的补充工具
- CoffeeScript:嘿,TypeScript 是 2012 年发布的!CoffeeScript 和 TypeScript 的区别在于 CoffeeScript 想要改进 JavaScript 语言,比如给 JavaScript 添加一些特性。这意味着要了解 CoffeeScript 与其输出的 JavaScript 的区别。随着时间推移,CoffeeScript 的最佳理念反而将其变成了另一个 JavaScript,人们为几乎成为了 JavaScript 的 CoffeeScript 感到困扰
- Flow:这是 Facebook 的 JavaScript 类型检查工具和 IDE 工具语言。就像 TypeScript 一样,Flow 为 JavaScript 添加了一些额外的语法支持,让你拥有了一个更加丰富的类型系统,然后在编译时再将其删除。当我刚开始写 JavaScript 时,Flow 是我最先使用的工具,因为它更接近标准的 JavaScript。Flow 是一个很棒的类型系统,它与 TypeScript 有着不同的目标。任何看不见的类型层系统都必须不断做出「正确」或者「感觉足够正确」的决定,Flow 的目标是「正确」(Flow 偏向于 soundness,在类型判断中更加悲观),而 TypeScript 的目标是「感觉上大部分情况都是 正确的」(而 TS 官方声称 TS 不是类型完备的,允许 unsound 行为,偏向于 completeness,在类型判断中更加乐观)。鱼和熊掌不可兼得,完备的类型推导、良好的开发体验和完美的 JS 协同(Perfect JavaScript Interop)只能取其二
那么,为什么大多数开源 Flow 代码库最终都迁移到了 TypeScript 呢?在我看来,很大程度上是由两个 团队不同的侧重点决定。Flow 是为了维护 Facebook 的代码库而建立的,而 TypeScript 是作为一种独立的语言建立的。这里有两个证据可以证明:
- Facebook 的代码库是一个不能被分割的巨大的 monorepo,而 Flow 团队为了使类型运行在这样的大代码库下做了大量令人难以置信的工作。另一方面,TypeScript 可以说是为构建小代码库服务(use projects to make sets of smaller codebases),因为这符合人们在开源社区中编写 JavaScript 模块的方式。我认为这么说很合理,TypeScript 不能像 Flow 一样运行在 Facebook 的 代码库上,它要么需要大量重写 Facebook 的代码来构建项目,要么需要对 TypeScript 进行大量 修改,这可能会影响到 TypeScript 整体开发者的体验
- 对比 DefinitelyTyped 和 Flow 对类型的做法,TypeScript 团队会轮值一名编译器工程师为 DefinitelyTyped 支持我们的构建工具,并帮助管理社区。而 Flow,它几乎完全由社区维护。DT 现在规模更大了,因为它们一直致力于非 Facebook 代码的开发,这将很难获得 Flow 团队的资金支持
微软给 TypeScript 在内部创造的独立环境让它可以自由专注于工具开发和整个生态系统的维护,而不是只专注于解决某个特别困难的问题。这让 TypeScript 团队能够与许多人合作,不断发布社区想要的功能。随着时间的推移,我猜想因为外部的需求增长放缓,Flow 团队越来越难为社区工作分配时间。这就形成了一个恶性循环。这使得 Flow 今天不再是 TypeScript 的直接「竞争者」,而是一个关于如何从不同的角度,使用不同的约束去解决类似的问题的有趣视角。
# TypeScript 的未来
# 对 TypeScript 的未来怎么看
目前阻碍人们使用 TypeScript 的最大障碍是它需要构建工具。我认为类型语法不太可能被加入 JavaScript 中,但是在 JavaScript 中「用注释的方式定义类型」的可能性非常大。这个想法是为 TypeScript 这样的类型系统创建一套语法,但是不定义 JS 运行时会发生什么。
const a: string = "1234"
// 将会变成这样
const a/*: string */ = "1234"
// 传入 JS 引擎
2
3
4
5
6
在这个例子中,JS 引擎会知道 : string 是一个类型注释,在 = 处结尾。这实际的工作方式是复杂的,需要时间来弄清楚。然而,让 TypeScript 能在 JavaScript 中「原生地」运行将降低它被使用的障碍。它会像 Babel 添加 TypeScript 支持时一样对 TypeScript 施加一些约束。但我觉得这是值得的。
Deno 是一个消除所有 TS 障碍的关键例子,它通过运行一个 Rust 编写的工具,能够非常快速地将 TS 编译到 JS,模拟了当前 JavaScript 引擎对原生 TypeScript 的支持。
# 如今的竞争者
- JetBrains WebStorm - 这是一个有高级 JavaScript 工具支持的 IDE。他们有自己的引擎用于重构、代码流分析并对 JavaScript 语法进行检查。这很好,JetBrains 在他们所有的 IDE 上都做了扎实的工作。我过去经常使用 AppCode 处理 iOS 的工作。当你有一个 TypeScript 项目时,WebStorm 会将 TypeScript 的语言工具和自己的工具混合在一起,这对你来说是双赢的
- 编译到 JS 的语言 - 目前的例子有 Elm,ReScript,KotlinScript,这些语言的核心目标是与JavaScript 交互。对于 TypeScript 来说,这些都是很有趣的语言,它们有一个干净的环境来实现类型系统 —— 也就是,没有 JS 包袱。作为竞争对手,它们倾向于更细分的市场,因为它们的核心不是 JavaScript ,并且社区也被从 CoffeeScript 迁移所困扰过
- WASM - 我听到 WASM 作为 TypeScript 竞争者的观点是,WASM 可以作为语言取代 JS 控制浏览器 DOM。反对这一观点的人普遍认为,WASM 没有 DOM 绑定,而且可能永远不会有。TypeScript 包含了 JavaScript 的缺点,如果你在 JavaScript 运行时中加入过 WASM 的话,你几乎总是会更加喜欢它。也就是说,AssemblyScript 在这方面做了一些很好的工作。也许把 WASM 想成 JSON 会更好,它是另一个组成项目的工具,不太可能成为 JavaScript 的竞争者,除非 WASM 和 DOM 的交互方式有所改变
- 编译到 WASM 的语言 - 比如 Rust,Go,Swift,等其它可以编译到 WASM 的语言。这些语言都可能占据 TypeScript 目前作为工具和 web 核心构建模块的位置,不过世事难料,谁知道会怎么样呢?这些语言能够提供各种不同的基本类型,并且基于不同的目标从头构建。如果 WASM 和 WASI 最终获得成功,那么我认为将会与平台相关(想想 apps 等功能实现),看看它们的发展方向会很有趣。说心里话,它们不会是 TypeScript 的竞争者,而是 JavaScript 的
# TypeScript 怎么看它在生态中的位置
TypeScript 希望在类型系统和编辑器工具领域进行创新。我们拥有在主流编程语言中表达能力最强的类型系统之一。
TypeScript 最初被创建时,对 JavaScript 进行修改的流程和现在非常不同,所以 TypeScript 中有一些特性实际上是 TC39 的领域,但仍然需要向后兼容。这些特性可能在 JavaScript 中存在很多年,并且经过 了多次迭代,这意味着 TypeScript 必须维护一个特定语言特性的两种版本。
所以我们的目标是成为 TC39 JavaScript 语言委员会的优秀成员,就编辑器支持的语言特性进行反馈,支持 TypeScript 用户想要看到的特性。通过这种协作方式,TC39 控制了 JavaScript,TypeScript 也支持他们。
# TypeScript 怎么看它的受众
TypeScript 的受众主要有:
- JavaScript 用户(作为语言工具)
- JS + JSDoc 用户(作为语言工具)
- TypeScript 用户(作为编译器,语言工具)
- TypeScript 严格模式(作为编译器,语言工具)
虽然项目使用 babel / swc / sucrase / esbuild 等工具构建时,tsc 是可选的,但是上面的几种受众仍然可以在每次或至少每两次 TS 版本发布中获得新特性(babel、esbuild 等会更新支持 TS 新特 性。可能是 TS 团队直接去这些项目里做,也可能会在没有 tsc 的情况下为这些项目提供特性,比如通过vscode。在 TS roadmap[10] 中可以了解更多发布计划)。
# TypeScript 是如何跟踪 JS 生态的
团队从以下几个方式听取反馈:
- GitHub issues 有持续不断的评论洪流
- 微软内部团队要求提供特性,或者要求我们帮忙调试他们缓慢的代码库
- 通过 Gitter 或者 TypeScript 社区的 Discord 与社区建立联系
- 通过微团的内部工具对想法 / 设计进行用户测试
- 与 VS Code 有着非常紧密的联系,许多语言工具的反馈都来自于他们
- 我们会阅读每一条 @ TypeScript 团队的推特
- 我们会跟踪迁移到 TypeScript 和从 TypeScript 迁走的博客文章
- 我们会跟踪行业调查和编程语言概述