即使使用类型保护检查对象属性的类型,也无法缩小对象属性的类型



TFlavour是一个歧视性并集,它是Object的一个值。

试图实现这一点,在js中有效,但ts很生气。ts游乐场连接

预期: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
}

问题是编译器不知道如何缩小对象属性(如IceCreams[item](的范围,在CCD_1中,您使用的键的类型未知为特定的文字类型。TypeScript仅遵循索引的类型,而不是标识。2的类型为CCD_ 3。如果你有item1item2,都是string类型,那么检查IceCreams[item1]不会让你得出关于IceCreams[item2]的任何结论,对吧?由于TypeScript无法区分item1item2itemitem之间的差异,因此无法缩小。这是在microsoft/TypeScript#10530上报告的TypeScript的已知限制。也许有一天它会被解决。但目前,有一个简单的解决方法:

只需将值复制到一个新变量中,这样问题索引只会发生一次:

iceCreamKeys.forEach(item => {
const x = IceCreams[item];
if (x.natural) {
console.log(x.naturalComponent)  // okay
}
})

游乐场链接到代码

与其直接使用索引访问项,不如尝试将其存储在单独的变量中。这样,TypeScript将识别正确的类型:

iceCreamKeys.forEach( item => {
const c = IceCreams[item]
if(c.natural){
console.log(c.naturalComponent) 
}
})

(工作TS游乐场(

iceCreamKeys.forEach( item => {
if(IceCreams.item.natural){
console.log(IceCreams.item.naturalComponent) // Accessing it like this worked
}
})

刚刚发现,这也有效。

最新更新