为什么Flow在访问数组元素时忽略了undefined的可能性?

3
这个函数存在一个bug。调用capitalize('')会抛出TypeError: Cannot read property 'toUpperCase' of undefined异常。
// @flow

function capitalize(str: string) {
  return str[0].toUpperCase() + str.slice(1)
}

这是因为:
var a = "foo" // : string
var b = a[0] // also : string

为什么类型推断认为b是一个string,而不是一个string|void,而后者似乎是b的正确类型?

这可以通过类型转换强制执行

return (str[0]: string|void).toUpperCase() + str.slice(1)


2
Flow 显然假定数组索引是有效的,并且字符串的所有元素也都是字符串。 - Barmar
1
@Barmar 我想知道假设数组索引严格不可为空的原因。我对这是否是一个错误持怀疑态度。这种行为必须是某种正确性权衡。 - Red Mercury
2
顺便说一下,这就是为什么你应该使用.charAt(0) :-) - Bergi
2
@RedMercury 当然,这是一种正确性权衡。如果您使用索引访问(无论是数组还是字符串),则应该只使用有效的索引(通常情况下也是如此)。当然,Flow 的能力不足以证明这一点。但是,如果它假定每次访问都可能返回“undefined”,那么它也会为正确的情况抛出很多错误/警告(或者强制您抑制它们)。 - Bergi
1
感谢@Bergi。var a = [1]; var b = a[100]是的,将b推断为number可能是有道理的。尽管这样做并不安全,但它将防止许多错误的结果。仍然令人惊讶的是,Flow决定这样做,因为Flow的主要设计原则之一是正确性(没有运行时异常)。 - Red Mercury
显示剩余5条评论
1个回答

4

来自文档

未定义的值和可选类型

未定义的值和null一样,也可能会引起问题。不幸的是,在JavaScript中,未定义的值是无处不在的,如果不严格限制使用,将会严重影响语言的可用性。例如,数组可能会存在元素缺失的情况;对象属性可以动态添加和删除。Flow忽略了从对象属性和数组元素访问导致的undefined可能性。更加严格的做法将强制程序员对每个数组元素或对象属性的解引用进行undefined检查(就像null检查一样),以便获得有用的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接