首页 > 解决方案 > 具有强类型属性的自定义类型中的类型假设

问题描述

考虑以下 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不保证值为dog(x)or的范围内fish

但是,因为is 的类型Dog._typeis"dog"类型,所以的值只能Fish._type是,值只能是。我不明白为什么"fish"Dog._type"dog"Fish._type"fish"

myPetMap[newPet._type].push(newPet);

是错误的。

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

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

因为这_type两种类型的属性类型Pet可能是一个固定值,所以我看不出在将 aDog添加到Fish数组时会出现任何类型不匹配问题,反之亦然。newPet._type为了将其添加到正确的数组中,不需要将其值具体化或已知。

有没有办法解决?任何 Typescript 编译器选项或不同的编写方式?

编辑:

的类型newPet._typestring

这是我在某一时刻的想法,但是试图改变 的值会newPet._type产生它自己的错误......

newPet._type = "Something Else";
[ts] Type '"Something Else"' is not assignable to type '"dog" | "fish"'. [2322]
(property) _type: "dog" | "fish"

标签: javascripttypescripttypes

解决方案


您的方法没有任何问题,但是您确实遇到了类型系统的限制。打字稿不能遵循变量之间的关系,所以打字稿不能告诉你的函数和这个函数之间的区别:

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

在上面的示例中,可以传入'dog'一个Fish. 虽然在你的情况下这是不可能发生的,因为_type来自newPet编译器不能遵循这个,它只是看到newPet._typeas的类型"dog" | "fish"并引发错误。

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


推荐阅读