TypeScript 中的类型谓词

Type predicates in TypeScript

这是 TypeScript 中缺少的功能还是经过深思熟虑的问题,如果条件逻辑被包装到一个单独的函数中,TS 编译器无法推断(然后缩小)参数的类型?我想到的是 TS 编译器在这种情况下给我的错误:

function isString(s) {
  return typeof s === 'string';
}

function toUpperCase(x: unknown) {
  if(isString(x)) {
    x.toUpperCase(); // ⚡️ x is still of type unknown
  }
}

但是,如果我去掉 isString 函数并在 if 语句中内联它的逻辑,那么 TS 编译器就会很好地识别该类型。

我知道我可以使用 as string 转换类型或使用类型谓词并在 isString 函数中使用 is string 类型注释。但是我刚开始思考——为什么TS不能缩小x.

的类型

实现这一点的一种方法是,如果编译器在执行控制流分析时内联了一些函数调用,这意味着:

function toUpperCase(x: unknown) {
  if (isString(x)) {
     x.toUpperCase(); 
  }
}

需要像 isString() 的正文这样展开来分析:

function toUpperCase(x: unknown) {
  if (typeof x === "string") {
    x.toUpperCase();
  }
}

GitHub 中谈论这个的规范问题是 microsoft/TypeScript#9998。该期中提出的问题是 "When a function is invoked, what should we assume its side effects are?" 并且似乎没有完美的答案。据说所有函数调用的全内联解决方案"wouldn't be even remotely practical"。 是否可以 完成浅内联,使 isString() 的行为如您所愿,而不会完全拖慢编译器?可能吧,但值得吗?不确定。看起来那里没有取得太大进展;如果您对此有足够强烈的感觉并且有一些令人信服的想法,您可以为 GitHub 问题做出贡献。


另一种工作方式是,如果编译器自动推断类型谓词 return 类型的正确类型 boolean-returning 函数,这意味着:

function isString(s: unknown) {
  return typeof s === "string";
}

需要这样推断:

function isString(s: unknown): s is string {
  return typeof s === "string";
}

GitHub 中谈论这个的规范问题是 microsoft/TypeScript#16069. A previous version of this was declined as being too complex 因为编译器能够分析每个 boolean-returning 函数和图形是不切实际的out 是否对其 return 类型有任何类似类型谓词的含义。不过,#16069 仍然开放,大概是为了采摘 "simple" 函数(如 x => typeof x === "string")的唾手可得的果实。同样,目前尚不清楚那里是否取得了任何进展,因此如果您对此有足够强烈的感觉并有一些令人信服的想法,您可以为 GitHub 问题做出贡献。


但如果我是你,在这两种情况下我都不会屏住呼吸。 TS3.6 的惯用解决方案是将 isString() 注释为用户定义的类型保护 returning s is string 并继续其他事情。

好的,希望对你有帮助。祝你好运!