又是一个"Object is possibly 'undefined'",不过真的不行

Yet another "Object is possibly 'undefined'", but it really can't be

TS 正在使用以下代码报告典型的 "Object is possibly 'undefined'" 错误,但该值不可能未定义。是什么导致报告此错误? link 到描述此行为的文档会很棒!

const maybeTrue = Math.random() < 0.5;

let myStr;

if (maybeTrue) {
  myStr = 'abc';
}

if (maybeTrue) {
  console.log(myStr.toLowerCase()); // Error here, `myStr` possibly undefined
}

Playground link

TypeScript 编译器对代码进行静态分析。这个分析揭示了读取myStr值的语句可以通过初始化myStr的代码路径到达(当第一个if的条件是true时)或者跳过初始化的代码路径。

编译器不会 运行 代码,它不会评估条件,它不会 "notice" 两个 if 语句使用相同的条件。

为了分析,两个 if 看起来都像 if (<condition>) { <statements> }。重要的是 <statements> 不会在所有代码路径上执行,因此在第一个 if 语句之后 myStr 可能会或可能不会被初始化。

正如在 playground 脚本中看到的那样。报错很明显,let声明了变量但没有初始化,所以是undefined.

然后根据您在条件句中的赋值推断出字符串类型。

我不相信打字稿编译器可以推断出在第二个条件中变量被初始化并且是一个字符串。我已经看到了一些与此相关的 GitHub 问题,很遗憾,我找不到 link 的任何问题。

但我们可以在您提供的 playground 中以某种方式对其进行测试:

  • 如果我们将变量初始化为空字符串,错误就会消失。
const maybeTrue = Math.random() < 0.5

let myStr = ""
if (maybeTrue) {
  myStr = 'abc'
}

if (maybeTrue) {
  console.log(myStr.toLowerCase())
}
  • 如果我们把console.log句移到第一个if,就不会报错
const maybeTrue = Math.random() < 0.5

let myStr = ""
if (maybeTrue) {
  myStr = 'abc'
  console.log(myStr.toLowerCase())
}

查看此处:https://www.typescriptlang.org/docs/handbook/type-inference.html and here https://www.typescriptlang.org/docs/handbook/advanced-types.html 了解有关如何实现类型的更多详细信息