8

在 TypeScript 中,如果启用了严格的 null 检查,我希望编译器会阻止我为变量赋值null或赋值,除非它承认.undefinednull

但是,数组访问似乎允许绕过此检查。

例子:

let a: string[] = ["Hello"];
let s: string;

// 1) this produces an error, as expected
s = undefined

// 2) s is undefined here, too, but no error
s = a[3];
console.log(s);

TypeScript Playground 上的可运​​行版本(注意:必须在“选项”对话框中启用“严格空值检查”)。

这里发生了什么?

  • 这是 TypeScript 编译器中的错误吗?
  • 还是故意遗漏?
  • 如果是后者,这是否记录在任何地方(最好有理由说明为什么这样做)?
4

2 回答 2

10

找到了 :-)。

tl; dr:这是故意的遗漏。数组访问在 TypeScript 代码中非常常见,对于开发人员来说,对每次访问都强制进行空/未定义检查被认为过于繁琐。

请注意,从 TypeScript 4.1 开始,这可以使用编译器选项进行配置 noUncheckedIndexedAccess。有关详细信息,请参阅 Klaster_1 的答案。


这个问题在讨论中被多次提出:

对 PR 7140 的评论有一个很好的理由来自 Anders Hejlsberg(核心开发人员之一):

索引只是生成匹配索引签名中声明的类型的值。undefined即使它在技术上更正确,如果我们自动添加到每个索引操作的类型中,那也太痛苦了。

例如,每个数组元素访问都必须伴随一个非空保护或!断言。我认为这会变得非常令人恼火。


个人评论:我认为这是一个合理的决定。这个问题是数组固有的 - 我认为(对于编译器)是否可以证明给定位置是否已定义,因为您可以使用计算出的位置。因此,任何警告都会产生许多误报,大多数开发人员都会将其关闭。

本质上,数组为开发人员提供了比编译器检查更多的自由度。如果您想要正确检查,我能看到的唯一解决方案是避免直接访问数组,并使用其他提供更多保护的数据结构。

于 2018-03-23T13:40:46.273 回答
3

TypeScript 4.1 引入了一个新的编译器选项 - noUncheckedIndexedAccess。除此之外,它还增加undefined了数组索引访问类型。

考虑以下片段(TS playground):

const items = [1,2,3]
console.log(items[1]?.toString(10))
console.log(items[2].toString(10))

没有noUncheckedIndexedAccess,items[2].toString(10)将被视为有效,并且在选项打开时无效。选项打开时将items[1]?.toString(10)有效,就像 Alex Neth 在旧答案中的评论一样。

于 2020-12-08T13:57:13.117 回答