gpt4 book ai didi

typescript - 如何使用 switch 语句来缩小使用条件类型的类型?

转载 作者:行者123 更新时间:2023-12-05 02:40:38 24 4
gpt4 key购买 nike

我有一个“食物”对象,它可以是多种类型,具体取决于“类别” Prop 的值。该对象来自一个json,所以之前不可能知道类型。

我试图在 category 属性上使用 switch 语句,以便将 Food 对象转换为正确的类型


export type Category = 'fruit' | 'grain' | 'meat'

interface Food<IngredientCategory extends Category> {
name: string;
category: IngredientCategory
[key: string]: string;
}

interface Fruit extends Food<'fruit'> {
color: string;
}

interface Grain extends Food<'grain'>{
size: string;
}

interface Meat extends Food<'meat'> {
temperature: string
}

type FoodFromCategory<IngredientCategory extends Category> = IngredientCategory extends 'fruit' ? Fruit : IngredientCategory extends 'grain' ? Grain : Meat;

const castFood = <IngredientCategory extends Category>(category: IngredientCategory, food: Food<any>):
Food<IngredientCategory> | undefined => {
switch (category) {
case "fruit":
return food as Fruit
case "grain":
return food as Grain
case "meat":
return food as Meat
}
return undefined
};


这会在返回的行上产生错误:

TS2322: Type 'Fruit' is not assignable to type 'Food'.   Types of property 'category' are incompatible.     Type '"fruit"' is not assignable to type 'IngredientCategory'.       '"fruit"' is assignable to the constraint of type 'IngredientCategory', but 'IngredientCategory' could be instantiated with a different subtype of constraint 'Category'.

为什么 switch 语句不缩小“IngredientCategory”通用参数的范围?还有其他方法可以做到这一点吗?

TS-Playground

最佳答案

目前这在 TypeScript 中是不可能的。 control flow analysis这缩小了 category 的类型不会缩小类型参数 IngredientCategory , 因此编译器无法推断出 Fruit可分配给 FoodFromCategory<IngredientCategory>即使category === "fruit" .

在这里寻求一些解决方案的规范问题可能是 microsoft/TypeScript#33912 , 并且有一些特定的功能建议如果实现可能会允许这样做,例如 microsoft/TypeScript#33014 .


但是现在,编译器不能自己做这件事,如果你想编译它,你需要做一些像 type assertion 这样的事情。告诉编译器它可以处理(例如)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
};

这有效并抑制了错误。但请注意,这是您将验证类型安全的责任从编译器上移开,并且您应该小心以确保正确执行此操作。


请注意,在运行时,switch 语句无论如何都没有做任何有用的事情。 JavaScript 不知道 FruitFoodFromCategory<IngredientCategory> ;所有这些都将作为 return food 发送给 JavaScript对于每个案例。如果你要去 return food不管怎样category是,你不妨写castFood而是这样:

const castFood = <IngredientCategory extends Category>(
category: IngredientCategory, food: Food<any>
) => food as FoodFromCategory<IngredientCategory>;

这完全消除了 switch陈述。它还消除了 undefined ,因为没有有效的方式来调用 castFood()如果category不在 IngredientCategory 中.

这就是所问问题的答案。退后一步,我有点担心你试图在这里做“ Actor ”; category参数在运行时根本不使用,所以它只是帮助编译器确定什么类型 food应该是。但在那种情况下,您可能最好使用 Fruit | Grain | Meat作为discriminated union与共同category属性,然后测试该属性,而不是将其作为单独的参数传递。

但是没有看到你打算如何或为什么调用 castFood()我不会假设朝那个方向冒险(但也许它看起来像 this code )。相反,我只是重申,通过控制流缩小泛型类型参数目前是不可能的,您将需要使用类型断言或其他一些类型松散技术来编译它。

Playground link to code

关于typescript - 如何使用 switch 语句来缩小使用条件类型的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68474835/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com