简体   繁体   English

即使在使用类型保护检查后,也无法缩小 object 属性的类型

[英]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?如果你有item1item2 ,两者都是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 无法区分item1item2itemitem之间的区别,因此无法缩小。 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
    }
})

Playground link to code Playground 代码链接

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM