为什么Typescript警告我,即使我已经验证了要从非空数组中删除元素,pop()
也可能返回undefined
?
type Person = {
name: string;
};
const people: Person[] = [{ name: 'Sandra' }];
if (people.length) {
const { name } = people.pop();
// TS Error: Property 'name' does not exist on type 'Person | undefined'.
}
即使我把保证写得更明确,也会得到同样的错误:
if (people.length > 0 && people[people.length - 1] !== undefined){
const { name } = people.pop();
// TS Error: Property 'name' does not exist on type 'Person | undefined'.
}
6条答案
按热度按时间zpgglvta1#
请参阅microsoft/TypeScript#30406以获取规范答案。
对于问题“为什么编译器认为即使我检查数组的
length
,pop()
也可能返回undefined
“,简短的回答是“因为TypeScript标准库对Array<T>
上的pop()
方法的调用签名返回T | undefined
“:因此,无论何时对数组调用
pop()
,返回值的类型都将包括undefined
。下一个合乎逻辑的问题是“为什么他们不做更好的调用签名,如果
length
为非零,则返回T
,如果length
为零,则返回undefined
?”对 that 的回答是“因为检查通用数组类型的length
属性不会改变数组的表观类型,因此调用签名无法区分”。例如,您可以添加一些调用签名,如下所示:
通过使用
this
参数,只有在调用方法得数组与指定得类型匹配时,才会选择每个调用签名.如果数组具有0
得length
,则返回undefined
.如果数组在键0
处具有T
类型得元素,则返回T
.对于长度固定且元素索引已知的元组类型,这将非常有效:
当然,在元组上调用
pop()
不是一个好主意,也不是你想要的。如果你有一个变长数组,并在它上面调用pop()
,两个调用签名都不会被选中,你会回到内置的T | undefined
,即使你试图检查length
:问题是
Array<T>
的length
属性是number
类型,并且没有“非零number
“类型来缩小w.length
的范围。为了支持这类事情,您需要像negated types这样的东西,它们不是TypeScript的一部分。通过充分的编译器工作,有人可以在TypeScript中为数组提供足够的结构,这样,对w.length
的真实性检查将把数组的类型缩小到可以调用pop()
的类型,而不必担心undefined
会被取出。但是这会给编译器和支持这种用例的语言增加大量的复杂性,好处不太可能超过代价。
如果没有这个,那么跳过
length
检查,直接调用pop()
,检查它是否是undefined
就容易多了。这对 you 来说是同样的工作量,因为它只是把检查从调用之前移到调用之后,这使得 * 编译器 * 的工作更简单。这里发布的其他答案建议了这个和其他的解决方案,所以我就不深入讨论了。我的主要观点是,该语言只是不允许
length
检查影响pop()
的行为。或者,正如@RyanCavanaugh(TS的开发负责人)在microsoft/TypeScript#30406中所写的,这不是我们能追踪到的
好吧!
Playground代码链接
wecizke32#
你可以这样做。
解决方案-2(弹出后!)
nzk0hqpo3#
可以使用
as
关键字Assertpop()返回的字符串如下:这告诉Typescript pop()正在返回一个字符串,而不是undefined。
igetnqfo4#
为什么不直接用
pop()
来检查值的存在性呢?当数组为空时,pop
方法返回undefined
。eni9jsuy5#
您可以使用“as”关键字或“!”来Assertarray.pop()不返回非空值或非未定义值。
for more information
mzsu5hc06#
输出量:
它解决了这个问题,然后你就可以得到名称了。但是可能是typescript无法将返回值Map到对象{ name }