[英]Can't narrow the type of an object property even after checking it with a type guard
TFlavour is a discriminatory union, which is then a value of an Object. TFlavour 是一个有区别的联合,它是一个 Object 的值。
Trying to implement this, works in js, but ts gets angry.试图实现这一点,在 js 中工作,但 ts 生气了。 ts playground link
ts游乐场链接
Expected: ts to understand discriminated unions in loops, as it understands it without loops预期: ts 理解循环中的可区分联合,因为它在没有循环的情况下理解它
type TFlavour = ({
natural: true,
naturalComponent : string
}) | ({
natural: false,
artificialComponent: string
})
type TIceCream = Record<string, TFlavour>
const IceCreams: TIceCream = {
CokeIceCream: {
natural:false,
artificialComponent: 'Coke'
},
Vanilla: {
natural: true,
naturalComponent: 'Vanilla Extract'
},
Mango: {
natural: true,
naturalComponent: 'Mango Fruit'
}
}
const iceCreamKeys = Object.keys(IceCreams)
iceCreamKeys.forEach( item => {
if(IceCreams[item].natural){
console.log(IceCreams[item].naturalComponent) // ts says "Property doesn't exists.."
}
})
if(IceCreams.Mango.natural){
console.log(IceCreams.Mango.naturalComponent) // Works here
}
The problem is that the compiler doesn't know how to do narrowing on an object property like IceCreams[item]
where you are indexing with a key whose type isn't known to be a specific literal type .问题是编译器不知道如何对像
IceCreams[item]
这样的 object 属性进行 缩小,在该属性中,您使用其类型未知为特定文字类型的键进行索引。 TypeScript is only following the type of the index, not the identity . TypeScript 仅遵循索引的类型,而不是标识。 And the type of
item
is string
.并且
item
的类型是string
。 If you have item1
and item2
, both of type string
, then checking IceCreams[item1]
wouldn't let you conclude anything about IceCreams[item2]
, right?如果你有
item1
和item2
,两者都是string
类型,那么检查IceCreams[item1]
不会让你得出任何关于IceCreams[item2]
的结论,对吧? And since TypeScript can't tell the difference between item1
vs item2
or item
vs item
, it can't narrow.而且由于 TypeScript 无法区分
item1
与item2
或item
与item
之间的区别,因此无法缩小。 This is a known limitation of TypeScript reported at microsoft/TypeScript#10530 .这是在microsoft/TypeScript#10530报告的 TypeScript 的已知限制。 Maybe someday it will be addressed.
也许有一天它会得到解决。 But for now, there's an easy workaround:
但就目前而言,有一个简单的解决方法:
Just copy the value into a new variable, so that the problematic indexing occurs only once:只需将值复制到一个新变量中,以便有问题的索引只发生一次:
iceCreamKeys.forEach(item => {
const x = IceCreams[item];
if (x.natural) {
console.log(x.naturalComponent) // okay
}
})
Instead of directly accessing the item with the index, try to store it in a separate variable.不要直接使用索引访问项目,而是尝试将其存储在单独的变量中。 This way, TypeScript will recognize the right type:
这样,TypeScript 将识别正确的类型:
iceCreamKeys.forEach( item => {
const c = IceCreams[item]
if(c.natural){
console.log(c.naturalComponent)
}
})
(working TS Playground ) (工作TS 游乐场)
iceCreamKeys.forEach( item => {
if(IceCreams.item.natural){
console.log(IceCreams.item.naturalComponent) // Accessing it like this worked
}
})
Just found out, this works too.刚发现,这也有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.