为什么我不能使用 switch 语句来缩小 Typescript 中的类类型?

问题描述

Playground link with comments

这是使用 interface 进行类型缩小的标准示例。

// 2 types of entity
enum EntityType {
  ANIMAL = 'ANIMAL',PLANT = 'PLANT',}

// animal has animal type and has legs attribute
interface Animal {
  entityType: EntityType.ANIMAL;
  legs: number;
}

//plant has plant type and has height attribute
interface Plant {
  entityType: EntityType.PLANT;
  height: number;
}

// generic entity is animal or plant
type Entity = Animal | Plant;

// operate on an entity
const doEntityThing = (entity: Entity) => {
  // can use type narrowing via switch based on entity.entityType
  switch(entity.entityType) {
    case EntityType.PLANT:
      return entity.height;
    case EntityType.ANIMAL:
      return entity.legs;
  }
};

在 switch 语句中,entity 的类型变窄了,因为 entity 可以成为的每个不同类型都有不同的 entityType,所以 TS 可以判断什么时候,比如说,{{ 1}} 是否有效。

但现在这里一个类似的例子,使用 entity.heightes 代替:

class

// 2 types of foods enum FoodType { MEAT = 'MEAT',VEG = 'VEG',} // base class for generic food class FoodBase { public constructor(public foodType: FoodType){} } // instances of meat class have food type meat and have doneness attribute class Meat extends FoodBase { public static foodType = FoodType.MEAT; public readonly foodType = Meat.foodType; public constructor(public doneness: 'rare' | 'burnt') { super(Meat.foodType); } } // instances of veg class have food type veg and have organic attribute class Veg extends FoodBase { public static foodType = FoodType.VEG; public readonly foodType = Veg.foodType; public constructor(public organic: boolean) { super(Veg.foodType); } } // generic food is meat or veg type Food = Meat | Veg; // operate on a food const doFoodThing = (food: Food) => { // can use instanceof to narrow the type of the food if(food instanceof Meat) { console.log(`This meat is ${food.doneness}.`); } else if(food instanceof Veg) { console.log(`This veg is${food.organic ? '' : ' not'} organic.`); } // can't use switch to narrow type! Why not? switch(food.foodType) { case FoodType.MEAT: console.log(food.doneness); // ERROR HERE! break; case FoodType.VEG: console.log(food.organic); // ERROR HERE! break; } }; 函数的参数是 doFoodThingMeat,两者具有不同的 Veg 属性。 Meat 总是有 foodType 'MEAT' 而 Veg 总是有 foodType 'VEG',所以不应该将参数的 foodType 缩小到 'MEAT' 意味着 food 参数应该有一个 foodType 属性吗?这似乎与上述示例中 doneness 的缩小情况相同。实体参数是 entityAnimal,并且使用 switch 语句缩小参数的 Plant 范围。

这两种缩小情况有什么不同,为什么一种有效而另一种无效?有没有办法使用 entityTypees 执行此操作并且仍然能够使用 class 语句?

解决方法

这是因为 VegMeat 的 'foodType' 被推断为类型 FoodType。为了使其工作,您应该将 Veg 的 foodType 指定为 FoodType.VEG,将 Meat 的 foodType 指定为 FoodType.MEAT:

class Meat extends FoodBase {
  public static foodType = FoodType.MEAT as const;
  // Or like this: public static foodType: FoodType.MEAT = FoodType.MEAT;
}

class Veg extends FoodBase {
  public static foodType = FoodType.VEG as const;
  // or like this: public static foodType: FoodType.VEG = FoodType.VEG;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...