具有严格空值检查的 TypeScript - 数组访问呢?
TypeScript with strict null checking - what about array access?
在 TypeScript 中,如果启用了严格的 null 检查,我希望编译器阻止我将 null
或 undefined
值分配给变量,除非它承认 null
。
但是,数组访问似乎允许绕过此检查。
示例:
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);
Runnable version on the TypeScript Playground(注意:"strict null checking" 必须在 "Options" 对话框中启用)。
这是怎么回事?
- 这是 TypeScript 编译器中的错误吗?
- 还是故意遗漏?
- 如果是后者,是否在任何地方记录了这一点(最好附上为什么这样做的理由)?
找到了:-).
tl;dr: 这是故意遗漏的。数组访问在 TypeScript 代码中非常常见,并且强制 null/undefined 检查每个访问对开发人员来说太麻烦了。
请注意,从 TypeScript 4.1 开始,这可以使用编译器选项 noUncheckedIndexedAccess
进行配置。详情请参阅 Klaster_1 的回答。
该问题已在讨论中多次提出:
- issue #11122 - Array lookup should return T | undefined
- comment on PR 7140
- #6229 - Proposal: strict and open-length tuple types
关于 PR 7140 的评论有一个来自 Anders Hejlsberg(核心开发人员之一)的很好的理由:
Indexing simply produces a value of the type declared in the matching
index signature. Even if it is technically more correct, it would
simply be too painful if we automatically added undefined
to the type
of every indexing operation.
For example, every array element access
would have to be accompanied by a non-null guard or a !
assertion. I
think that would become hugely irritating.
个人评价:我认为这是一个合理的决定。这个问题是数组固有的——我认为不可能证明(对于编译器)给定位置是否已定义,因为您可以使用计算出的位置。所以任何警告都会产生很多误报,而且大多数开发人员都会将其关闭。
本质上,数组为开发人员提供了比编译器可以检查的更多的自由。如果你想正确检查,我能看到的唯一解决方案是避免直接数组访问,并使用其他提供更多保护的数据结构。
TypeScript 4.1 introduced a new compiler option - 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 在旧答案中的评论一样。
在 TypeScript 中,如果启用了严格的 null 检查,我希望编译器阻止我将 null
或 undefined
值分配给变量,除非它承认 null
。
但是,数组访问似乎允许绕过此检查。
示例:
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);
Runnable version on the TypeScript Playground(注意:"strict null checking" 必须在 "Options" 对话框中启用)。
这是怎么回事?
- 这是 TypeScript 编译器中的错误吗?
- 还是故意遗漏?
- 如果是后者,是否在任何地方记录了这一点(最好附上为什么这样做的理由)?
找到了:-).
tl;dr: 这是故意遗漏的。数组访问在 TypeScript 代码中非常常见,并且强制 null/undefined 检查每个访问对开发人员来说太麻烦了。
请注意,从 TypeScript 4.1 开始,这可以使用编译器选项 noUncheckedIndexedAccess
进行配置。详情请参阅 Klaster_1 的回答。
该问题已在讨论中多次提出:
- issue #11122 - Array lookup should return T | undefined
- comment on PR 7140
- #6229 - Proposal: strict and open-length tuple types
关于 PR 7140 的评论有一个来自 Anders Hejlsberg(核心开发人员之一)的很好的理由:
Indexing simply produces a value of the type declared in the matching index signature. Even if it is technically more correct, it would simply be too painful if we automatically added
undefined
to the type of every indexing operation.For example, every array element access would have to be accompanied by a non-null guard or a
!
assertion. I think that would become hugely irritating.
个人评价:我认为这是一个合理的决定。这个问题是数组固有的——我认为不可能证明(对于编译器)给定位置是否已定义,因为您可以使用计算出的位置。所以任何警告都会产生很多误报,而且大多数开发人员都会将其关闭。
本质上,数组为开发人员提供了比编译器可以检查的更多的自由。如果你想正确检查,我能看到的唯一解决方案是避免直接数组访问,并使用其他提供更多保护的数据结构。
TypeScript 4.1 introduced a new compiler option - 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 在旧答案中的评论一样。