复杂的 TypeScript 推理

Sophisticated TypeScript inference

我有一个代码:

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之外什么都不是?我的意思是,因为我总是依赖类型推断,所以有时我可能不会注意到这样的事情。有没有办法让它更严格,或者对于这种情况有什么最佳实践吗?谢谢。

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...
    }

哈希图类型

根据您的要求,您可以将 Zoo 接口替换为 hashmap 类型,该类型允许任意数量的 [=14= 类型的条目(或属性,如果您想这样称呼它们) ]:

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 };

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