typescript - 即使在使用类型保护检查之后也无法缩小对象属性的类型

标签 typescript discriminated-union

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。如果您有 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
    }
})

Playground link to code

关于typescript - 即使在使用类型保护检查之后也无法缩小对象属性的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73666799/

相关文章:

f# - 在 F# 中比较带有 < 和 > 的可区分联合案例

reactjs - 声明第三方库的已定义属性

angular - 引用错误 : "__decorate is not defined" when passing input to an angular directive

html - 在 React 的 onFocus 期间区分键盘和鼠标事件

F# 类型构造函数不像函数

f# - 如何将大型可区分联合树转换为可读形式?

f# - v3.1中命名联合字段的编译形式

reflection - F# 可区分联合的拆箱值

typescript 类型 T 或函数 () => T 用法

javascript - 从多个嵌套数组创建新数据对象集