在 JavaScript 中,总会用多种方式对某个值进行检查,然后根据不同类型的值执行不同的操作。 TypeScript 能够理解这些检查,并将它们称作为类型守卫。 我们不需要在变量的每一个使用位置上都指明类型,TypeScript 的类型检查器能够利用基于控制流的分析技术来检查是否在前面使用了类型守卫。
例如,可以这样写
这个例子中,我们检查 是否为 类型。 TypeScript 识别出了 检查,它被当作是一个类型守卫,并且知道在 分支内 的类型为 。 这样就可以正常地访问 类型上的方法,例如 。
但如果我们将条件表达式提取到一个名为 的常量会发生什么?
在之前版本的 TypeScript 中,这样做会产生错误 - 就算 的值为类型守卫,TypeScript 也会丢掉这个信息。 这不是想要的结果,因为我们可能想要在不同的地方重用这个检查。 为了绕过这个问题,通常需要重复多次代码或使用类型断言。
在 TypeScript 4.4 中,情况有所改变。 上面的例子不再产生错误! 当 TypeScript 看到我们在检查一个常量时,会额外检查它是否包含类型守卫。 如果那个类型守卫操作的是 常量,某个 属性或某个未修改的参数,那么 TypeScript 能够对该值进行类型细化。
不同种类的类型守卫都支持,不只是 类型守卫。 例如,对于可辨识联合类型同样适用。
在 TypeScript 4.4 版本中对判别式的分析又进了一层 - 现在可以提取出判别式然后细化原来的对象类型。
另一个例子,该函数会检查它的两个参数是否有内容。
TypeScript 知道如果 为 那么 和 都存在。 也就是说不需要编写像 这样的非空断言的代码来告诉 TypeScript 不为 。
一个好的性质是该分析同时具有可传递性。 TypeScript 可以通过这些常量来理解在它们背后执行的检查。
注意这里会有一个截点 - TypeScript 并不是毫无限制地去追溯检查这些条件表达式,但对于大多数使用场景而言已经足够了。
这个功能能让很多直观的 JavaScript 代码在 TypeScript 里也好用,而不会妨碍我们。 更多详情请参考 PR !
TypeScript 支持使用索引签名来为对象的每个属性定义类型。 这样我们就可以将对象当作字典类型来使用,把字符串放在方括号里来进行索引。
例如,可以编写由 类型的键映射到 值的类型。 如果我们给它赋予 类型以外的值会报错。
虽说在这里 可能是更适合的数据结构 (具体的说是 ),但 JavaScript 对象通常更方便或者正是我们要操作的目标。
相似地, 已经定义了 索引签名,我们可以插入和获取 类型的值。
索引签名是一种非常有用的表达方式。 然而,直到现在它们只能使用 和 类型的键( 索引签名存在一个有意为之的怪异行为,它们可以接受 类型的键,因为 会被转换为字符串)。 这意味着 TypeScript 不允许使用 类型的键来索引对象。 TypeScript 也无法表示由一部分 类型的键组成的索引签名 - 例如,对象属性名是以 字符串开头的索引签名。
TypeScript 4.4 解决了这个问题,允许 索引签名以及模版字符串。
例如,TypeScript 允许声明一个接受任意 值作为键的对象类型。
相似地,可以定义带有模版字符串的索引签名。 一个场景是用来免除对以 开头的属性名执行的 TypeScript 额外属性检查。 当传递一个对象字面量给目标类型时,TypeScript 会检查是否存在相比于目标类型的额外属性。
最后,索引签名现在支持联合类型,只要它们是无限域原始类型的联合 - 尤其是:
- 模版字符串(例如 )
带有以上类型的联合的索引签名会展开为不同的索引签名。
更多详情请参考 PR 。
在 JavaScript 中,允许使用 语句抛出任意类型的值,并在 语句中捕获它。 因此,TypeScript 从前会将异常捕获变量的类型设置为 类型,并且不允许指定其它的类型注解:
当 TypeScript 引入了 类型后,对于追求高度准确性和类型安全的用户来讲在 语句的捕获变量处使用 成为了比 类型更好的选择,因为它强制我们去检测要使用的值。 后来,TypeScript 4.0 允许用户在 语句中明确地指定 (或 )类型,这样就可以根据情况有选择一使用更严格的类型检查; 然而,在每一处 语句里手动指定 是一件繁琐的事情。
因此,TypeScript 4.4 引入了一个新的标记 。 它将 语句捕获变量的默认类型由 改为 。
这个标记属性于 标记家族的一员。 也就是说如果你启用了 ,那么该标记也自动启用了。 在 TypeScript 4.4 中,你可能会看到如下的错误:
如果我们不想处理 语句中 类型的捕获变量,那么可以明确使用 类型注解,这样就会关闭严格类型检查。
更多详情请参考 PR 。
在 JavaScript 中,读取对象上某个不存在的属性会得到 值。 与此同时,某个已有属性的值也允许为 值。 有许多 JavaScript 代码都会对这些情况一视同仁,因此最初 TypeScript 将可选属性视为添加了 类型。 例如,
等同于:
这意味着用户可以给 明确地指定 值。
因此默认情况下,TypeScript 不区分带有 类型的属性和不存在的属性。 虽说这在大部分情况下是没问题的,但并非所有的 JavaScript 代码都如此。 像是 , ,对象展开( )和 - 循环这样的函数和运算符会区别对待属性是否存在于对象之上。 在 例子中,如果 属性的存在与否是至关重要的,那么就可能会导致运行时错误。
在 TypeScript 4.4 中,新的 标记指明了可选属性的确切表示方式,即不自动添加 类型:
该标记不是 标记家族的一员,需要显式地开启。 该标记要求同时启用 标记。 我们已经更新了 DefinitelyTyped 以及其它的声明定义来帮助进行平稳地过渡,但你仍可能遇到一些问题,这取决于代码的结构。
更多详情请参考 PR 。
TypeScript 4.4 支持了 类中的 语句块 ,一个即将到来的 ECMAScript 特性,它能够帮助编写复杂的静态成员初始化代码。
在静态语句块中允许编写一系列语句,它们可以访问类中的私有字段。 也就是说在初始化代码中能够编写语句,不会暴露变量,并且可以完全访问类的内部信息。
若不使用 语句块也能够编写上述代码,只不过需要使用一些折中的 hack 手段。
一个类可以有多个 语句块,它们的运行顺序与编写顺序一致。
感谢 Wenlu Wang 为 TypeScript 添加了该支持。 更多详情请参考 PR 。
TypeScript 的 选项完全更新了! 感谢 Song Gao ,我们更新了编译选项的描述 和 菜单的配色样式 。
更多详情请参考 Issue 。
TypeScript 现在会缓存下内部符号是否可以在不同上下文中被访问,以及如何显示指定的类型。 这些改变能够改进 TypeScript 处理复杂类型时的性能,尤其是在使用了 标记来生成 文件的时候。
更多详情请参考 PR 。
TypeScript 经常需要对文件路径进行 “标准化” 操作来得到统一的格式,以便编译器能够随处使用它。 它包括将反斜线替换成正斜线,或者删除路径中间的 和 片段。 当 TypeScript 需要处理成千上万的路径时,这个操作就会很慢。 在 TypeScript 4.4 里会先对路径进行快速检查,判断它们是否需要进行标准化。 这些改进能够减少 5-10% 的工程加载时间,对于大型工程来讲效果会更加明显。
更多详情请参考 PR 以及 PR 。
TypeScript 现在会缓存构造的路径映射(通过 里的 )。 对于拥有数百个路径映射的工程来讲效果十分明显。 更多详情请参考 PR 。
这曾是一个缺陷,在 模式下,如果启用了 则 TypeScript 会重新进行类型检查。 这导致了不管是否开启了 构建速度都挺慢。 TypeScript 4.4 修复了这个问题,该修复也应用到了 TypeScript 4.3 里。
更多详情请参考 PR 。
TypeScript 4.4 优化了为超大输出文件生成 source map 的速度。 在构建旧版本的 TypeScript 编译器时,结果显示节省了 8% 的生成时间。
感谢 David Michon 提供了这项简洁的优化 。
当在工程引用上使用了 模式时,TypeScript 必须执行 “是否更新检查” 来确定是否需要重新构建。 在进行 构建时,该检查是无关的,因为每个工程依赖都要被重新构建。 在 TypeScript 4.4 里, 会避免执行无用的步骤并进行完整的构建。 更多详情请参考 PR 。
TypeScript 为在 Visual Studio 和 Visual Studio Code 等编辑器中的 JavaScript 编写体验赋能。 大多数情况下,在处理 JavaScript 文件时,TypeScript 会置身事外; 然而,TypeScript 经常能够提供有理有据的建议且不过分地侵入其中。
这就是为什么 TypeScript 会为 JavaScript 文件提供拼写建议 - 不带有 的 文件或者关闭了 选项的工程。 即,TypeScript 文件中已有的 "Did you mean...?" 建议,现在它们也作用于 JavaScript 文件。
这些拼写建议也暗示了代码中可能存在错误。 我们在测试该特性时已经发现了已有代码中的一些错误!
更多详情请参考 PR !
TypeScript 4.4 支持了内嵌提示特性,它能帮助显示参数名和返回值类型等信息。 可将其视为一种友好的 “ghost text”。
该特性由 Wenlu Wang 的 PR 所实现。
他也在 Visual Studio Code 里进行了集成 并在 July 2021 (1.59) 发布 。 若你想尝试该特性,需确保安装了稳定版 或 insiders 版本的编辑器。 你也可以在 Visual Studio Code 的设置里修改何时何地显示内嵌提示。
当 Visual Studio Code 显示补全列表时,包含自动导入在内的补全列表里会显示指向模块的路径; 然而,该路径通常不是 TypeScript 最终替换进来的模块描述符。 该路径通常是相对于 workspace 的,如果你导入了 包,你大概会看到 这样的路径 。
这些路径很难处理且容易产生误导,尤其是插入的路径同时需要考虑 Node.js 的 解析,路径映射,符号链接以及重新导出等。
这就是为什么 TypeScript 4.4 中的补全列表会显示真正的导入模块路径。