TFlavour 是一个可区分的联合,它是一个对象的值。
试图实现这个,在 js 中工作,但 ts 生气了。 ts playground link
预期: 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
}
最佳答案
问题是编译器不知道怎么做narrowing在像 IceCreams[item]
这样的对象属性上,您正在使用其类型未知的键进行索引 literal type . TypeScript 仅遵循索引的类型,而不是身份。 item
的类型是string
。如果您有 item1
和 item2
,两者都是 string
类型,那么检查 IceCreams[item1]
不会让您对 IceCreams[item2]
有任何结论,对吗?由于 TypeScript 无法区分 item1
与 item2
或 item
与 item
之间的区别,因此它不能狭窄。这是在 microsoft/TypeScript#10530 中报告的 TypeScript 的已知限制。 .也许有一天它会得到解决。但目前,有一个简单的解决方法:
只需将值复制到一个新变量中,这样有问题的索引只会出现一次:
iceCreamKeys.forEach(item => {
const x = IceCreams[item];
if (x.natural) {
console.log(x.naturalComponent) // okay
}
})
关于typescript - 即使在使用类型保护检查之后也无法缩小对象属性的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73666799/