Typescript 复杂的打字推断

Typescript 复杂的打字推断,typescript,typescript2.0,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];

我有一个密码:

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-biote:Cat=cats[I]
,但是有没有可能让TS猜到它除了猫之外什么都不能做呢?我的意思是,因为我总是依赖类型推断,有时我可能不会注意到这样的事情。有没有一种方法可以使它更严格,或者对于这种情况有什么最佳实践?谢谢。

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

您有三个选项来断言类型
Cat
:类型强制转换、类型保护和hashmap类型

类型转换

当您确定
Cat
的所有属性都是
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...
    }
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"...
类型防护装置

如果您不确定
Cat
的所有属性是否为
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类型,该类型允许任意数量的
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...
    }
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开始,不允许使用此语法:


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

这是不可能的。它可以是猫以外的其他东西。当您说
cats:Zoo
时,您是说
cats
对象必须至少实现
Zoo
。它可以实现其他接口并具有其他属性,这些属性可能不是
Cat
s。这不是“至少”。TypeScript可以编写类似于
let cats:Zoo
的东西的原因是
let
允许以后初始化变量。如果在以后的某个时刻,您想将某个内容分配给
cats
,则必须满足接口的要求。由于成员不是可选的,assignedment必须设置所有三个。做一些类似于
cats={bobtail:{meow:true}}。@SebastianSebald:问题在于没有分配属性以满足接口。问题在于,对象可以提供其他不同类型的属性。当您没有在代码中创建对象时(例如,当您从JSON反序列化对象时),您根本不能保证接口会得到满足。@Sefe Yes。我只想纠正“至少”的说法。实际上,您可以在authors代码中看到这一点。
Zoo
接口正在使用
hasOwnProperty
,尽管他从未定义过它;)@SebastianSebald:正如我所说的,如果
cats
来自JSON(或者
any
的简单转换),那么
Zoo
的一些属性实际上可能是未定义的(或者是不同类型的)。