具有强类型属性的自定义类型中的类型假设

时间:2019-07-12 17:32:27

标签: javascript typescript types

请考虑以下Typescript类型...

export type Dog = {
    color: string,
    earsFloppy: boolean,
    _type: "dog"
}

export type Fish = {
    color: string,
    finsFlowy: boolean,
    _type: "fish"
}

export type Pet = Dog | Fish;

export type PetMap = {
    dog: Dog[],
    fish: Fish[]
}

考虑以下功能(也在Typescript中)...

var myPetMap = { dog: [], fish: [] };

function addToPetMap(newPet: Pet): void {
    myPetMap[newPet._type].push(newPet);    
}

我的项目中的设置几乎相同,但是出现以下错误:

  

[ts] Cannot invoke an expression whose type lacks a call signature. Type '((...items: Dog[]) => number) | ((...items: Fish[]) => number)' has no compatible call signatures. [2349]

但是执行以下操作可以解决问题...

var myPetMap = { dog: [], fish: [] };

function addToPetMap(newPet: Pet): void {
    switch(newPet._type) {
        case 'dog':
            myPetMap[newPet._type].push(newPet);
        break;
        case 'fish':
            myPetMap[newPet._type].push(newPet);
        break;
    }
}

newPet._type存在的范围内,好像myPetMap[newPet._type].push(newPet)的值必须是已知的或具体的。它不能存在于不能保证newPet._type(x)或dog的范围内。

但是,由于fish type Dog._type,而"dog" type Fish._type"fish"的值可以仅为Dog._type,而"dog"的值可以仅为Fish._type。我不明白为什么

"fish"

是错误的。

当传入的myPetMap[newPet._type].push(newPet); Pet时,Dog只能是newPet._type并且新的宠物将被添加到"dog"中,这是myPetMap["dog"]个对象的数组。

当传入的DogPet时,Fish只能是newPet._type并且新的宠物将被添加到"fish"中,这是myPetMap["fish"]个对象的数组。

由于Fish可能是两种类型的_type属性的类型都是固定值,所以我看不出{{1} }被添加到Pet数组中,反之亦然。无需将Dog的值具体化或已知即可将其添加到正确的数组中。

有什么办法解决吗?是否有Typescript编译器选项或其他编写方式?

编辑:

  

Fish的类型为newPet._type

这是我当时的想法,但是尝试更改newPet._type的值会产生自己的错误...

string
newPet._type

1 个答案:

答案 0 :(得分:3)

您的方法没有错,但是您确实遇到了类型系统的限制。 Typescript无法遵循变量之间的关系,因此Typescript无法分辨您的函数与该函数之间的区别:

function addToPetMap(_type: "dog" | "fish", newPet: Pet): void {
    myPetMap[_type].push(newPet);    
}

在上面的示例中,可以传入'dog'和一个Fish的实例。虽然在您的情况下这是不会发生的,因为_type来自newPet,编译器无法遵循此要求,它只是将newPet._type的类型视为"dog" | "fish"并引发错误。

您使用开关的解决方法是这样做的非常安全的方法。类型断言也是合适的。