【问题标题】:Type 'N[P]' cannot be used to index type 'IComponents<N>'类型“N[P]”不能用于索引类型“IComponents<N>”
【发布时间】:2020-02-08 04:27:25
【问题描述】:

我试图在打字稿中实现实体组件系统模式。我有一个实体类,我想在其中保留实体的组件。我想为这个模式创建独立的包并在我的其他项目中使用它。

这是我有错误的实体类。

type IComponents<N> = {
  [P in keyof N]?: Component<any, N>;
}

// eslint-disable-next-line @typescript-eslint/interface-name-prefix
export interface EntityType<N> {
  id: string;
  components: IComponents<N>;
  addComponent(component: Component<any, N>): void;
  removeComponent(componentId: N): void;
  print(): void;
}

export default class Entity<N> implements EntityType<N> {
  readonly id: string;
  components: IComponents<N> = {};

  constructor() {
    this.id = v4();
  }

  addComponent(component: Component<any, N>): void {
    this.components[component.name] = component;
  }

  removeComponent(componentName: N): void {
    delete this.components[componentName];
  }

  print(): void {
    console.log(JSON.stringify(this, null, 4));
  }
}

addComponents 方法中我得到了这个错误 Type 'N' cannot be used to index type 'IComponents&lt;N&gt;'.

这是Component 类的签名

export default abstract class Component<P, N> {
  readonly id: string;
  readonly name: N;
  props: P;

  protected constructor(props: P, name: N) {
    this.props = props;
    this.name = name;
    this.id = v4();
  }
}

有一个项目我使用这个包:

为组件创建组件、实体和枚举

export enum EComponents {
  position,
}


export default (): Entity<EComponents> => {
  const player = new Entity<EComponents>();
  player.addComponent(new PositionComponent());

  return player;
};

获取实体并处理它的系统。在这种方法中,我想从entity.components 特定组件中获取并处理它

 update(entity: Entity): void {
    const component: PositionComponent | null = this.getComponent(entity);

    if (!component) return;

    const { x = 0, y = 0 } = component.props;
    const position = { x, y };

    if (this.keyboard.isKeyPressed('KeyW')) {
      position.y -= 3;
    }

    if (this.keyboard.isKeyPressed('KeyA')) {
      position.x -= 3;
    }

    if (this.keyboard.isKeyPressed('KeyS')) {
      position.y += 3;
    }

    if (this.keyboard.isKeyPressed('KeyD')) {
      position.x += 3;
    }

    entity.components['Position'].props = position;
  }

【问题讨论】:

  • 我不明白你的 NP 命名约定。 P 是某种属性类型,N 是某种名称类型,对吧?所以我希望N 本身就是字符串。但是你有很多keyof N 到处走动,所以我不确定。无论如何,你会得到一个错误,因为你试图使用N 作为键是keyof N,而不是N 的索引。你需要解决这个差异。不过,我不知道如何告诉你这样做,因为我真的不明白代码的意图。祝你好运!
  • 是的,P 是一些属性,N 是枚举,其中保留了组件的名称。我想从实体类中的字段components 中获取组件列表。
  • 您能否为您的枚举添加代码以及您打算如何使用Entity 类并调用其方法? (也就是说,你能发一个minimal reproducible example吗?)你可能混淆了枚举values,它的类型Enum是数字或字符串与枚举object的联合>,其类型typeof Enum 是从名称到这些数字或字符串的映射。如果N 是枚举值类型,那么你不想使用keyof N。另一方面,如果N 是枚举对象的类型,那么您不想使用N 作为索引。在addComponent 中,您似乎同时在做这两件事,这是一个错误。
  • 感谢您的关注。我更新了我的问题,添加了更多代码示例。
  • 很抱歉,但这仍然不构成minimal reproducible example,如How to Ask 指南中所述,这是一个好问题。请熟悉这些准则,这样您就可以增加获得好答案的机会。 最小 可重现的示例也意味着从您的问题中删除 代码,除非它与您的问题直接相关。一个最小的可重现示例意味着其他任何人都应该能够将代码放入 IDE 并看到您所看到的相同问题,而无需解决未解决的第 3 方依赖项。

标签: typescript entity-component-system


【解决方案1】:

我写了两种类型IComponentsIMappedComponentsIComponents 用于从 Component 扩展的组件列表。第二种类型 IMappedComponents 用于 Entity 中对象的组件列表。

export type IComponents<N extends keyof any> = {
  [P in N]?: Component<any, N>;
};


export type IMappedComponents<N extends keyof any, C extends IComponents<N>> = {
  [P in N]?: C[P];
};

// eslint-disable-next-line @typescript-eslint/interface-name-prefix
export interface EntityType<N extends keyof any, C extends IComponents<N>> {
  id: string;
  components: IMappedComponents<N, C>;
  addComponent(component: C[N]): void;
  removeComponent(componentId: N): void;
  print(): void;
}

export default class Entity<N extends keyof any, C extends IComponents<N>> implements EntityType<N, C> {
  readonly id: string;
  components: IMappedComponents<N, C> = {};

  constructor() {
    this.id = v4();
  }

  addComponent(component: C[N]): void {
    if (component) {
      this.components[component.name] = component;
    }
  }

  removeComponent(componentName: N): void {
    delete this.components[componentName];
  }

  print(): void {
    console.log(JSON.stringify(this, null, 4));
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-11
    • 2022-11-15
    • 2018-04-01
    • 2017-05-23
    • 1970-01-01
    • 2018-02-13
    • 2023-01-31
    • 2021-10-24
    相关资源
    最近更新 更多