问题描述
从 forEach
回调函数内部设置变量时,该变量的类型似乎不正确。一个简单的例子:
let foo: (string | null) = null;
[1,2,3].forEach((i) => {
foo = "bar";
});
if(foo == null) {
throw new Error("not found")
}
# Typescript complains that `length` is not a property of type `never`
console.log(foo.length)
就在 forEach
之后,我希望 foo
的类型为 string | null
,但实际上它只是 null
。在 console.log
行中,我希望它只是 string
,但实际上它是 never
(因为我们已经消除了 null
作为 {{1} } 投掷。
重要的是,上面的代码(减去 Error
位)在纯 JavaScript 中工作得非常好 - 这纯粹是我和 TypeScript 编译器以某种方式无法正常通信的情况。
无论如何:
- 如果有人能解释为什么这样我就可以更好地理解 Typescript 了,我会很高兴
- 我该如何解决这个问题?我可以在 console.log 之前打一个
: (string | null)
,但肯定有更好的方法吗?
解决方法
这是控制流分析的权衡之一。
通过注释 string | null
类型,您告诉编译器该变量显然需要任一类型的值。然后您对 null
进行赋值,这让编译器将类型缩小到 null
。
您希望 TypeScript 考虑回调内部的分配并放弃缩小范围,但事实并非如此。这是团队在决定作为参数传递给高阶函数的函数中发生的突变是否应该泄漏到外部作用域时所做的权衡。
请参阅关于此问题的 this source repo 讨论。
,这不是 TypeScript 的行为,而是 EcmaScript 的行为。 forEach
定义了变量的作用域,所以里面发生的事情,它仍然留在里面。