为什么 <array>.[n] 类型不同于 <array>.at(n)
Why <array>.[n] type are different from <array>.at(n)
我正在尝试从使用 <array>.at()
切换到 <array>.[]
以保持一致性。但这是我 运行 遇到的一个问题:
const array: string[] = [];
if (array[0]) {
const item = array[0]; // string
}
if (array.at(0)) {
const item = array.at(0); // string | undefined
}
if (array[0]) {
const item = array.at(0); // string | undefined
}
为什么类型不同?我错过了什么?我已经阅读了有关 at()
方法的信息,但是关于 typescript 的信息并不多。
typescript@4.6.4
有了那些 if (array[0])
风格的类型保护(特别是因为你现在说你启用了 noUncheckedIndexedAccess
选项),可以说答案只是 TypeScript 不会缩小类型函数调用。毕竟,在一般情况下,函数可以在每次调用时 return 不同的值(并非所有函数都是 纯 )。
你可以用 const
:
锁定它
// Note: `noUncheckedIndexedAccess` enabled
const array: string[] = [];
if (array[0]) {
const item = array[0];
// ^? −−−− string
console.log(array[0]); // string
}
const item1 = array.at(0);
if (item1) {
console.log(item1);
// ^? −−−− string
}
但这提出了一个有趣的问题,即为什么 没有 守卫是不同的(如果你 没有 noUncheckedIndexedAccess
已启用)?
const array: string[] = [];
const i1 = array[0];
// ^? −−−− string
const i2 = array.at(0);
// ^? −−−− string | undefined
我怀疑原因有两个:
很久以前,TypeScript 团队做出了务实的决定,即(默认情况下¹)索引访问数组(如 string[]
)应该 return 数组的元素类型( string
),而不是数组的元素类型或 undefined
(string | undefined
),尽管后者是对 property access 的更正确解释(这才是真正的索引访问)以及您确实可以从中获得 undefined
的运行时现实。想象一下,如果没有它们,TypeScript 代码会有多笨拙! Every 数组访问将涉及一个 | undefined
,它最终会用 non-null 断言或其他任何东西乱扔代码。所以他们采取了务实的方法。
at
method 的范围比一般的索引访问要小得多——它根本不打算在任何地方取代索引访问,它的主要用例是索引为负数时。所以它的类型反映了它可能 return undefined
的事实,因为 不会 到处都需要 non-null 断言——只有在那些地方您使用 at
而不是索引访问。因此,没有理由不符合规范,在这种情况下,类型与规范保持一致更有用。
¹ 关于“默认”:您 可以 告诉 TypeScript 您希望索引访问通过 noUncheckedIndexedAccess
option 包含 | undefined
。启用该选项后,我上面的示例变为:
// With `noUncheckedIndexedAccess` enabled
const array: string[] = [];
const i1 = array[0];
// ^? −−−− string | undefined <== Changed
const i2 = array.at(0);
// ^? −−−− string | undefined
我正在尝试从使用 <array>.at()
切换到 <array>.[]
以保持一致性。但这是我 运行 遇到的一个问题:
const array: string[] = [];
if (array[0]) {
const item = array[0]; // string
}
if (array.at(0)) {
const item = array.at(0); // string | undefined
}
if (array[0]) {
const item = array.at(0); // string | undefined
}
为什么类型不同?我错过了什么?我已经阅读了有关 at()
方法的信息,但是关于 typescript 的信息并不多。
typescript@4.6.4
有了那些 if (array[0])
风格的类型保护(特别是因为你现在说你启用了 noUncheckedIndexedAccess
选项),可以说答案只是 TypeScript 不会缩小类型函数调用。毕竟,在一般情况下,函数可以在每次调用时 return 不同的值(并非所有函数都是 纯 )。
你可以用 const
:
// Note: `noUncheckedIndexedAccess` enabled
const array: string[] = [];
if (array[0]) {
const item = array[0];
// ^? −−−− string
console.log(array[0]); // string
}
const item1 = array.at(0);
if (item1) {
console.log(item1);
// ^? −−−− string
}
但这提出了一个有趣的问题,即为什么 没有 守卫是不同的(如果你 没有 noUncheckedIndexedAccess
已启用)?
const array: string[] = [];
const i1 = array[0];
// ^? −−−− string
const i2 = array.at(0);
// ^? −−−− string | undefined
我怀疑原因有两个:
很久以前,TypeScript 团队做出了务实的决定,即(默认情况下¹)索引访问数组(如
string[]
)应该 return 数组的元素类型(string
),而不是数组的元素类型或undefined
(string | undefined
),尽管后者是对 property access 的更正确解释(这才是真正的索引访问)以及您确实可以从中获得undefined
的运行时现实。想象一下,如果没有它们,TypeScript 代码会有多笨拙! Every 数组访问将涉及一个| undefined
,它最终会用 non-null 断言或其他任何东西乱扔代码。所以他们采取了务实的方法。at
method 的范围比一般的索引访问要小得多——它根本不打算在任何地方取代索引访问,它的主要用例是索引为负数时。所以它的类型反映了它可能 returnundefined
的事实,因为 不会 到处都需要 non-null 断言——只有在那些地方您使用at
而不是索引访问。因此,没有理由不符合规范,在这种情况下,类型与规范保持一致更有用。
¹ 关于“默认”:您 可以 告诉 TypeScript 您希望索引访问通过 noUncheckedIndexedAccess
option 包含 | undefined
。启用该选项后,我上面的示例变为:
// With `noUncheckedIndexedAccess` enabled
const array: string[] = [];
const i1 = array[0];
// ^? −−−− string | undefined <== Changed
const i2 = array.at(0);
// ^? −−−− string | undefined