8 月 28 日微软正式发布了 TypeScript 3.6 版,本文将主要介绍 TypeScript 3.6 版中的更新内容,包括:语言和编译器、新的 TypeScript Playground、编辑功能等。
我们很高兴地宣布,TypeScript 3.6 正式面世了!
有些人可能还不太了解 TypeScript,这里做一个简单介绍:TypeScript 是一种基于 JavaScript 的语言,在后者的基础上添加了可选的静态类型;TypeScript 编译器可以检查这些类型以捕获程序中的常见错误(例如属性拼写错误和函数调用错误等);然后可以使用 TypeScript 编译器和 Babel 等工具将基于最前沿规范编写的 TypeScript 代码转换为符合标准的 ECMAScript 代码,后者可在任何浏览器或运行时(甚至是只支持 ES3 或 ES5 的旧版本)上运行。
TypeScript 不仅具备类型检查和较新的 ECMAScript 功能,其编辑工具也是业界一流水平,是 TypeScript 项目不可或缺的一部分;多种类型的编辑器为 TypeScript 提供了代码自动完成、重构和快速修复等功能。如果你在 Visual Studio 或 Visual Studio Code 中编辑过 JavaScript 文件,其实这些体验是由 TypeScript 提供的,所以你可能已经在不知情的情况下开始使用 TypeScript 了!
你可以查看TypeScript官方网站了解更多信息。TypeScript 可以通过NuGet获取,或在 npm 中键入以下命令:
可选的编辑器有:
Visual Studio Code 的说明。
不久的将来我们还会提供其他编辑器的支持。
下面来看看 3.6 版中的更新内容吧!
语言和编译器
更严格的生成器
TypeScript 3.6 对迭代器和生成器函数的检查更严格了。在早期版本中,用户使用生成器时无法判断一个值是从生成器 yield 还是返回的。
此外,生成器之前会假定 yield 的类型总是 any。
TypeScript 3.6 中的检查器现在知道第一段代码中的 curr.value 的正确类型应该是 string,并且在第二段代码中调用 next()时会正确地报错。这是因为 Iterator 和 IteratorResult 类型声明中现在引入了一些新的类型参数,且新版 TypeScript 会用 Generator 这个新类型来表示生成器。
Iterator 类型现在允许用户指定 yield 类型、返回的类型以及 next 可以接受的类型。
在此基础上,新的 Generator 类型是一个 Iterator,它总是同时存在 return 和 throw 方法,并且也是可迭代的。
为了区分返回值和生成值,TypeScript 3.6 将 IteratorResult 类型转换为差别联合类型:
简而言之,这意味着你在直接处理迭代器时能够适当地缩小迭代器的值。
为了正确表示可以从调用 next()传递给生成器的类型,TypeScript 3.6 还可以在生成器函数主体内推断出某些 yield 用法。
如果你更喜欢显式方法,那么还可以强制可以用 yield 表达式执行返回、yield 和计算的值的类型使用显式返回类型。下面的例子中,next( )只能用布尔值调用,并且根据 done 的值,value 可以是 string 或 number。
这部分更改的详情可参阅github。
更准确的数组扩展
在目标为 ES2015 之前的版本中,诸如 for/of 循环和数组扩展之类的结构用的发射有些复杂。因此 TypeScript 默认使用更简单的发射,只支持数组类型,并支持使用–downlevelIteration 标志在其他类型上迭代。在此标志下发出的代码更准确,但体积也大得多。
默认情况下–downlevelIteration 是关闭的,因为以 ES5 为目标的用户多数只使用带数组的迭代结构。但某些边缘情况下只支持数组的发射还是有一些可见的差异。
例如,以下示例
等同于下列数组:
但是,TypeScript 会将原始代码转换为下面的代码:
它们是有些不一样的。Array(5)生成一个长度为 5 的数组,但没有定义的属性槽!
当 TypeScript 调用 slice()时,它还会创建一个其索引尚未设置的数组。
这可能不太好理解,但其实有许多用户遇到了这种麻烦。TypeScript 3.6 不再使用 slice()和内置函数,而是引入了一个新的__spreadArrays
助手,将 ECMAScript 2015 的内容在较旧的目标中模拟出来,不用 --downlevelIteration。 __spreadArrays 也可以在tslib中使用(如果你想缩小包的体积,那么非常值得一试)。
有关更多信息,请参阅资料。
改进了 Promise 相关的用户体验
Promise 是当今最常用的异步数据方法之一。然而面向 Promise 的 API 通常会让用户感到困惑。TypeScript 3.6 引入了一些改进,避免用户错误处理 Promise。
例如,在将 Promise 的内容传递给另一个函数之前,人们往往会忘记.then()或 await 这部分内容。TypeScript 现在有了对应的错误消息,并告知用户他们可能应该使用 await 关键字。
在 await 或.then()一个 Promise 之前就尝试访问方法也是很常见的错误。这类错误很多,我们都做了改进。
这里的目的是就算用户没意识到要 await,起码这些消息能给出一些提示。
除了改进 Promise 相关的错误消息外,我们现在还在某些情况下提供了快速修复。
有关更多详细信息,请参阅原始问题及相关链接。
对标识符的 Unicode 支持改进
当发射到 ES2015 及更高版本的目标时,TypeScript 3.6 对标识符的 Unicode 字符提供了更好的支持。
SystemJS 中的 import.meta 支持
当 module 目标设置为 system 时,TypeScript 3.6 支持将 import.meta 转换为 context.meta。
在环境上下文中允许 get 和 set 访问器
以前的 TypeScript 版本不允许在环境上下文中 get 和 set 访问器(例如在 declare-d 类中,或者在.d.ts 文件中)。理由是对于这些属性的读写而言访问器与属性没有区别;但是因为 ECMAScript 的类字段提案可能与现有 TypeScript 版本中的行为不同,我们意识到我们需要一种方法来对接这种行为差异,以便在子类中提供适当的错误。
因此,用户现在可以在 TypeScript 3.6 的环境上下文中编写 getter 和 setter。
在 TypeScript 3.7 中编译器也将利用此功能,以便生成的.d.ts 文件也发射 get/set 访问器。
环境类和函数可以合并
在以前版本的 TypeScript 中,任何情况下合并类和函数都是错误的。现在环境类和函数(具有 declare 修饰符或在.d.ts 文件中的类/函数)可以合并了。这意味着现在你可以编写以下代码:
这样就用不着再写成:
这样做的一个优点是可以很容易地表达可调用的构造函数模式,同时还允许名称空间与这些声明合并(因为 var 声明不能与 namespace 合并)。
在 TypeScript 3.7 中,编译器也将利用此功能,以便从.js 文件生成的.d.ts 文件可以正确捕获类函数的可调用性和可构造性。
更多详细信息请参阅 GitHub 上的原始PR。
为–build 和–incremental 提供 API 支持
TypeScript 3.0 开始支持引用其他项目,并使用–build 标志以增量方式构建它们。之后 TypeScript 3.4 引入了–incremental 标志来保存之前编译的相关信息,这样就可以只重建特定文件了。这些标志可以帮助用户更快、灵活地构建项目。可惜这些标志无法用于 Gulp 和 Webpack 这样的第三方构建工具。TypeScript 3.6 现在公开了两组 API 来处理项目引用和增量程序构建。
创建–incremental 构建时用户可以利用 createIncrementalProgram 和 createIncrementalCompilerHost API。用户还可以使用新公开的 readBuilderProgram 函数从这个 API 生成的.tsbuildinfo 文件中重新保存旧程序实例,该函数仅用于创建新程序(你无法修改返回的实例,它仅用于其他 create*Program 函数中的 oldProgram 参数)。
针对项目引用方面,新版引入了一个新的 createSolutionBuilder 函数,它返回一个新类型 SolutionBuilder 的实例。
有关这些 API 的详细信息可参阅资料。
新的 TypeScript Playground
应用户呼吁,新版 TypeScript Playground 做了大幅改进,引入了许多全新功能。新版 Playground 基本上是社区流行的Artem Tyurin的TypeScript Playground的一个 fork。我们在这里非常感谢 Artem 提供的帮助!
新版 Playground 提供了许多新选项,包括:
target 选项(允许用户从 es5 切换到 es3、es2015、esnext 等)
所有严格标志(包括 strict)
支持纯 JavaScript 文件(使用 allowJS 和可选的 checkJs)
这些选项在共享 Playground 样本时也能使用,让用户可以更可靠地共享示例,无需告诉收件人“哦,别忘了打开 noImplicitAny 选项!”。
在不久的将来,我们将改进 Playground 样本功能、添加 JSX 支持、改进自动类型获取等,让用户使用 Playground 时如同在使用自己的编辑器一样。
我们欢迎大家在GitHub上提交反馈和请求!
编辑功能
分号感知代码编辑
Visual Studio 和 Visual Studio Code 等编辑器可以自动应用快速修复、重构、自动从其他模块导入值等转换。这些转换由 TypeScript 提供支持,而旧版本的 TypeScript 会无条件地在每个语句的末尾添加分号;但很多用户不喜欢这种风格,不希望编辑器自动插入分号。
TypeScript 现在变得非常聪明,可以在应用这些编辑时检测你的文件是否使用分号。如果你的文件不怎么用分号的话 TypeScript 也不会添加分号。
更多详细信息请参阅资料。
更智能的自动导入
JavaScript 有许多不同的模块语法或约定:ECMAScript 标准是一种、Node 支持的一种(CommonJS)、AMD 一种、System.js 又是一种,还有更多!在大多数情况下 TypeScript 默认使用 ECMAScript 模块语法来自动导入,遇到有些使用不同编译器设置的 TypeScript 项目就不怎么合适,在使用纯 JavaScript 和 require 调用的 Node 项目中也不搭配。
TypeScript 3.6 变得更聪明了一些,可以先查看你现有的导入后再决定怎样自动导入其他模块。你可以在此处查看更多信息。
重大更新
命名为“constructor”的类成员现在是构造函数
根据 ECMAScript 规范,使用名为 constructor 的方法的类声明现在是构造函数,无论它们是使用标识符名称还是字符串名称声明都是如此。
注意有一个例外,就是计算属性的名称等于“constructor”的情况。
DOM 更新
新版 lib.dom.d.ts 中的许多声明已被删除或更改。具体包括(但不限于)以下内容:
全局 window 不再定义为类型 Window——而是将其定义为类型 Window&typeof globalThis。在某些情况下,最好将其类型称为 typeofwindow。
GlobalFetch 已经移除了,取而代之的是 WindowOrWorkerGlobalScope。
Navigator 上的某些非标准属性消失了。
experimental-webgl 上下文移除了。替代品是 webgl 或 webgl2。
JSDoc 注释不再合并
在 JavaScript 文件中,TypeScript 只会在 JSDoc 注释之前确定声明的类型。
关键字不能包含转义序列
以前关键字允许包含转义序列。TypeScript 3.6 中就不行了。
未来计划
想要了解官方团队未来要开展的工作,请查看今年 7 月至 12 月的半年路线图计划。
我们希望这个新版本能继续改善你的开发体验。你有任何建议或遇到任何问题我们都很感兴趣,欢迎大家在GitHub上提交反馈。
英文原文:https://devblogs.microsoft.com/typescript/announcing-typescript-3-6/
评论