'CustomEnum.Case'可以分配给'T'类型的约束,但可以用不同的约束'CustomEnum'子类型实例化。 [英] 'CustomEnum.Case' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'CustomEnum'

查看:0
本文介绍了'CustomEnum.Case'可以分配给'T'类型的约束,但可以用不同的约束'CustomEnum'子类型实例化。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在定义一个接口,其中一个属性类型依赖于绑定到枚举的泛型参数P。我使用以下方法:

export enum Scopes {
  Fruit = 'fruit',
  Vegetables = 'vegetables',
}

export enum FruitItemTypes {
  Strawberry = 'strawberry',
  Rasberry = 'rasberry'
}

export enum VegetableItemTypes {
  Potatoes = 'potatoes',
  Carrots = 'currency',
}


export type ItemTypes = FruitItemTypes | VegetableItemTypes

interface ItemTypeForScope {
  [Scopes.Fruit]: FruitItemTypes;
  [Scopes.Vegetables]: VegetableItemTypes;
}

export interface Item {
  id: string;
  type: ItemTypes;
}
export interface ScopedItem<T extends Scopes> extends Item {
  type: ItemTypeForScope[T];
}
export interface ScopedData<T extends Scopes> {
  items: ScopedItem<T>[];
}

export type Data = { [scope in Scopes]: ScopedData<scope> };

我还想使用ScopedItem<T>作为以下函数的返回类型:

const getItemType = <T extends Scopes>(data: Data, scope: T): ScopedItem<T>[] => {
    return data[scope].items 
}

但是,我收到以下错误,但根据我的说法,泛型参数T最终将是枚举案例之一。

Type 'ScopedItem<Scopes.Fruit>[] | ScopedItem<Scopes.Vegetables>[]' is not assignable to type 'ScopedItem<T>[]'.
  Type 'ScopedItem<Scopes.Fruit>[]' is not assignable to type 'ScopedItem<T>[]'.
    Type 'ScopedItem<Scopes.Fruit>' is not assignable to type 'ScopedItem<T>'.
      Type 'Scopes.Fruit' is not assignable to type 'T'.
        'Scopes.Fruit' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Scopes'.

playground

推荐答案

我相信这里的问题与this issue中描述的问题相同...您希望编译器将{[K in Scopes]: ScopedData<K>}[P]计算为类似ScopedData[P]的值,其中P是扩展K的泛型类型参数。但编译器不会进行这种高阶推理,即在解析泛型类型之前简化具体类型的泛型函数;在某些情况下已经有一个suggestion来实现这一点,但在TS3.5中还没有。

所以,变通办法...编译器可以验证以下内容:

const getItemType = <T extends Scopes>(
  data: Data,
  scope: T
): Data[T]["items"] => {
  return data[scope].items;
};
不是将data[scope].items的类型作为ScopedItem<T>[]返回,而是将其作为Data[T]["items"]返回。这些将被证明是相同的,并且当您实际对具体类型的scope参数调用getItemType()时,它将以相同的具体类型结束。


或者您可以直接承认您的推理能力优于编译器,并使用type assertion让编译器知道谁是老大:

const getItemTypeAssertion = <T extends Scopes>(
  data: Data,
  scope: T
): ScopedItem<T>[] => {
  return (data[scope] as ScopedData<T>).items; // I am smarter than the compiler 🤓
};

希望其中一个能为您工作。祝你好运!

Link to code

这篇关于&#39;CustomEnum.Case&#39;可以分配给&#39;T&#39;类型的约束,但可以用不同的约束&#39;CustomEnum&#39;子类型实例化。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆