我有一个“Food”对象,它可以有多种类型,具体取决于“category”属性的值。该对象来自json,因此之前不可能知道类型。
\n我正在尝试在类别道具上使用 switch 语句,以便将 Food 对象转换为正确的类型
\n\nexport type Category = \'fruit\' | \'grain\' | \'meat\'\n\ninterface Food<IngredientCategory extends Category> {\n name: string;\n category: IngredientCategory\n [key: string]: string;\n}\n\ninterface Fruit extends Food<\'fruit\'> {\n color: string;\n}\n\ninterface Grain extends Food<\'grain\'>{\n size: string;\n}\n\ninterface Meat extends Food<\'meat\'> {\n temperature: string\n}\n\ntype FoodFromCategory<IngredientCategory extends Category> = IngredientCategory extends \'fruit\' ? Fruit : IngredientCategory extends \'grain\' ? Grain : Meat;\n\nconst castFood = <IngredientCategory extends Category>(category: IngredientCategory, food: Food<any>):\n Food<IngredientCategory> | undefined => {\n switch (category) {\n case "fruit":\n return food as Fruit\n case "grain":\n return food as Grain\n case "meat":\n return food as Meat\n }\n return undefined\n};\n\n\nRun Code Online (Sandbox Code Playgroud)\n这会在返回的行上产生错误:
\n\n\nTS2322:类型“Fruit”不可分配给类型“Food”。\xc2\xa0\xc2\xa0属性\'category\'的类型不兼容。\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0Type \'"fruit"\' 不可分配给类型 \'IngredientCategory\'。\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\'"fruit"\' 可分配给类型为 \'IngredientCategory\' 的约束,但 \'IngredientCategory\'可以用约束“类别”的不同子类型来实例化。
\n
为什么 switch 语句不缩小“IngredientCategory”通用参数的范围?我还有其他方法可以做到这一点吗?
\n\n目前这在 TypeScript 中是不可能的。缩小类型的控制流分析category不会缩小类型参数 IngredientCategory,因此编译器无法推断出可分配Fruit给FoodFromCategory<IngredientCategory>Even if category === "fruit"。
这里要求某种解决方案的规范问题可能是microsoft/TypeScript#33912,并且有一些特定的功能建议如果实现的话可能允许这样做,例如microsoft/TypeScript#33014。
但目前,编译器本身无法做到这一点,如果您希望编译它,您将需要执行类似类型断言之类的操作来告诉编译器它可以将(例如)Fruit视为FoodFromCategory<IngredientCategory>:
const castFood = <IngredientCategory extends Category>(
category: IngredientCategory, food: Food<any>
): FoodFromCategory<IngredientCategory> | undefined => {
switch (category) {
case "fruit":
return food as Fruit as FoodFromCategory<IngredientCategory>
case "grain":
return food as Grain as FoodFromCategory<IngredientCategory>
case "meat":
return food as Meat as FoodFromCategory<IngredientCategory>
}
return undefined
};
Run Code Online (Sandbox Code Playgroud)
这有效并抑制了错误。但请注意,这是您将验证类型安全的责任从编译器中移开,并且您应该小心确保正确执行此操作。
请注意,在运行时, switch 语句无论如何都没有做任何有用的事情。JavaScript 不知道Fruitor FoodFromCategory<IngredientCategory>;对于每种情况,所有这些都会被发送到 JavaScript return food。如果你不管怎样return food,category你不妨castFood这样写:
const castFood = <IngredientCategory extends Category>(
category: IngredientCategory, food: Food<any>
) => food as FoodFromCategory<IngredientCategory>;
Run Code Online (Sandbox Code Playgroud)
这完全消除了该switch声明。它还消除了undefined,因为没有有效的方法来调用castFood()if categoryis not in IngredientCategory。
这就是所问问题的答案。退一步来说,我有点担心你是否试图在这里进行“转换”;该category参数在运行时根本不使用,因此它只是帮助编译器确定food应该是什么类型。但在这种情况下,您可能最好将其用作公共属性的可区分联合Fruit | Grain | Meat,然后测试该属性,而不是将其作为单独的参数传递。category
但是,如果不知道您打算如何或为什么打电话,castFood()我不会假设朝这个方向冒险(但也许它看起来像这段代码)。相反,我只是重申,通过控制流缩小泛型类型参数目前是不可能的,并且您将需要使用类型断言或其他一些类型松散技术来使其编译。
| 归档时间: |
|
| 查看次数: |
5759 次 |
| 最近记录: |