使用括号表示法访问对象 属性 时键入缩窄符
Type narrowing breaks when accessing an object property with bracket notation
为什么测试 1 和 2 在这里工作,但测试 3 在 foo[barConst]++
: 'Object is possibly "undefined".' 处显示编译器错误?我经常需要通过括号表示法访问属性,因此喜欢为这些属性设置常量,但 TypeScript 不允许这样做。它也不适用于 const enum
s。这是错误还是有充分的错误原因?
const barConst = 'bar';
interface Foo {
[barConst]?: number;
}
function test1(foo?: Foo) {
if (foo && foo.bar) {
foo.bar++;
}
}
function test2(foo?: Foo) {
if (foo && foo['bar']) {
foo['bar']++;
}
}
function test3(foo?: Foo) {
if (foo && foo[barConst]) {
foo[barConst]++; // compiler error: 'Object is possibly "undefined".'
}
}
继续评论讨论。 (我仍然不知道你在找什么)
你可以尝试这样的事情:
type barConst = 'bar';
type Foo<K extends string> = Record<K, number>;
function test3(foo?: Foo<barConst>) {
if (typeof foo !== 'undefined') {
foo['bar']++;
}
}
let x: Foo<barConst> = { bar: 2 };
test3(x);
console.log(x);
您可以自动完成并且没有编译器错误。
不过,请更新您的问题。
通过计算的 propertyNames/literal 表达式缩小 属性 访问范围目前似乎是不可能的。看看这个 issue and its PR, also that issue.
您可以使用字符串文字缩小 属性 访问范围,例如 foo["bar"]
。 foo[barConst]
等动态表达式不起作用。将 foo[barConst]
分配给一个变量,然后将 working/narrowing 分配给该变量是一种替代方法,但需要额外的声明。
在您的情况下,最简单的解决方案是使用非空断言运算符 !
强制转换表达式。当您对虚假值进行预检查时,您在这里是安全的:
function test3(foo?: Foo) {
if (foo && foo[barConst]) {
foo[barConst]!++;
}
}
随着 TypeScript 4.7 的发布,由于它改进了括号元素访问的控制流分析,原始代码不再导致编译器错误,因为 foo && foo[barConst]
守卫现在正确地缩小了foo[barConst]
访问类型为 number
。
有关 CFA 总体更新的更多详细信息,请参阅 PR #40617。
为什么测试 1 和 2 在这里工作,但测试 3 在 foo[barConst]++
: 'Object is possibly "undefined".' 处显示编译器错误?我经常需要通过括号表示法访问属性,因此喜欢为这些属性设置常量,但 TypeScript 不允许这样做。它也不适用于 const enum
s。这是错误还是有充分的错误原因?
const barConst = 'bar';
interface Foo {
[barConst]?: number;
}
function test1(foo?: Foo) {
if (foo && foo.bar) {
foo.bar++;
}
}
function test2(foo?: Foo) {
if (foo && foo['bar']) {
foo['bar']++;
}
}
function test3(foo?: Foo) {
if (foo && foo[barConst]) {
foo[barConst]++; // compiler error: 'Object is possibly "undefined".'
}
}
继续评论讨论。 (我仍然不知道你在找什么) 你可以尝试这样的事情:
type barConst = 'bar';
type Foo<K extends string> = Record<K, number>;
function test3(foo?: Foo<barConst>) {
if (typeof foo !== 'undefined') {
foo['bar']++;
}
}
let x: Foo<barConst> = { bar: 2 };
test3(x);
console.log(x);
您可以自动完成并且没有编译器错误。 不过,请更新您的问题。
通过计算的 propertyNames/literal 表达式缩小 属性 访问范围目前似乎是不可能的。看看这个 issue and its PR, also that issue.
您可以使用字符串文字缩小 属性 访问范围,例如 foo["bar"]
。 foo[barConst]
等动态表达式不起作用。将 foo[barConst]
分配给一个变量,然后将 working/narrowing 分配给该变量是一种替代方法,但需要额外的声明。
在您的情况下,最简单的解决方案是使用非空断言运算符 !
强制转换表达式。当您对虚假值进行预检查时,您在这里是安全的:
function test3(foo?: Foo) {
if (foo && foo[barConst]) {
foo[barConst]!++;
}
}
随着 TypeScript 4.7 的发布,由于它改进了括号元素访问的控制流分析,原始代码不再导致编译器错误,因为 foo && foo[barConst]
守卫现在正确地缩小了foo[barConst]
访问类型为 number
。
有关 CFA 总体更新的更多详细信息,请参阅 PR #40617。