TypeScript

抑制类型收缩

对于一个可变变量,可采用 函数返回 而不是 直接变量 来使用,防止其在进行可分配比对时产生错误的收缩。错误的收缩尤其在枚举类型使用上会发生。变量是支持可变的,但任何变量的 union类型 在被守卫后(xxx === true,被守卫为boolean),类型空间中会产生收缩,向内作用域就被指定了类型,失去 union 的特性(可能是任意某一项),通过函数返回则可以避免这种收缩。
image.png
编译器本身依赖于对解析器中 token 变量进行修改的副作用,例如:

  1. if (token === SyntaxKind.ExportKeyword) {
  2. nextToken();
  3. if (token === SyntaxKind.DefaultKeyword) {
  4. // We have "export default"
  5. }
  6. ...
  7. }

这在 #9407 中成为了一个错误,因为编译器依然认为在调用 nextToken 之后, token 的值是 SyntaxKind.ExportKeyword,因此在将 token 与 SyntaxKind.DefaultKeyword 比较时报错。
我们将改为使用一个函数来获取当前 token:

  1. if (token() === SyntaxKind.ExportKeyword) {
  2. nextToken();
  3. if (token() === SyntaxKind.DefaultKeyword) {
  4. // We have "export default"
  5. }
  6. ...
  7. }

这个函数非常简单:

  1. function token(): SyntaxKind {
  2. return currentToken;
  3. }

由于所有现代 JavaScript 虚拟机都内联了这样的简单函数,因此不会降低程序的性能。
Anders 认为这种通过使用函数访问可变状态来抑制类型缩小的模式是合理的。

实际效果:

  1. import * as ts from 'typescript'
  2. ts.SyntaxKind.ForStatement
  3. let token: ts.SyntaxKind = 6;
  4. function tokenF(): ts.SyntaxKind {
  5. return token;
  6. }
  7. function test() {
  8. if (token === ts.SyntaxKind.ExportKeyword) {
  9. if (token === ts.SyntaxKind.DefaultKeyword) {
  10. }
  11. }
  12. }
  13. function test1() {
  14. if (tokenF() === ts.SyntaxKind.ExportKeyword) {
  15. if (tokenF() === ts.SyntaxKind.DefaultKeyword) {
  16. // We have "export default"
  17. }
  18. }
  19. }

image.png