复杂的TypeScript推理

时间:2017-04-12 07:50:36

标签: typescript typescript2.0

我有一个代码:

interface Cat{ meow:boolean }

interface Zoo{ bobtail:Cat, bengal:Cat, cheetoh:Cat }

然后,代码中的某个地方:

let cats:Zoo;// imagine it's set correctly somewhere
for(const i in cats)
   if(cats.hasOwnProperty(i)){
        const creature=cats[i];
        /// well, the "creature" is of type "any" here...
   }

当然我可以在这里做const creature:Cat = cats[i],但有可能让TS猜测它除了Cat之外什么都不可能吗?我的意思是,因为我总是依赖类型推断,有时我可能不会注意到这样的事情。是否有一种方法可以使其更严格,或者对于像这样的案例是否有任何最佳实践?谢谢。

1 个答案:

答案 0 :(得分:2)

Typescript不能保证所有属性都是Cat类型。对象cats可以具有比接口中定义的更多的属性,并且它们的类型在编译时是未知的。只有在运行时才能确定对象具有哪个属性以及它们的类型。

您有三个选项来断言类型Cat:类型转换,类型保护和散列映射类型。

输入

当您确定所有 cats的属性属于Cat类型时,您只需将结果转换为Cat

let cats:Zoo;// imagine it's set correctly somewhere
for(const i in cats)
    if(cats.hasOwnProperty(i)){
        const creature=cats[i] as Cat;
        ///the "creature" is of type "Cat" now...
    }

警卫

如果您不确定Cats的所有属性是否属于Cat类型,则可以使用类型保护。这只会考虑具有正确类型的值:

//Define type guard
function isCat(value: any): value is Cat {
    return value.hasOwnProperty('meow');
}

//...

let cats:Zoo;// imagine it's set correctly somewhere
for(const i in cats)
    const creature=cats[i];
    if (cats.hasOwnProperty(i) && isCat(creature)) {
        ///the "creature" is of type "Cat" within the block...
    }

Hashmap类型

根据您的要求,您可以将Zoo接口替换为散列映射类型,该类型允许类型为Cat的任意数量的条目(或者如果您想这样调用它们的属性):

type Zoo = { [key: string]: Cat };
let cats:Zoo;// imagine it's set correctly somewhere
for(const i in cats)
    const creature=cats[i];
    ///the "creature" is of type "Cat"...

此解决方案的缺点是您无法像在示例中使用界面那样设置特定的属性名称。从TypeScript 2.2开始,此语法 not 允许:

type Zoo = { ["bobtail" | "bengal" | "cheetoh"]: Cat };

在许多情况下,这不是问题,在此解决方案中,您不需要任何额外的步骤,如强制转换和类型保护,因为可以推断出类型。