Тип 'N [P]' нельзя использовать для индексации типа 'IComponents <N>' - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь реализовать шаблон системы компонентов сущности в машинописи. У меня есть класс для сущностей, где я хочу сохранить компоненты сущности. Я хочу создать независимый пакет для этого шаблона и использовать его в других моих проектах.

Это класс Entity, в котором у меня есть ошибка.

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<N>'.

Это подпись для 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();
  }
}

Существует проект, в котором я использую этот пакет:

Создание компонента, объекта иenum для компонентов

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;
  }

1 Ответ

0 голосов
/ 20 октября 2019

Я написал два типа IComponents и IMappedComponents. IComponents для списка компонентов, который простирается от 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));
  }
}
...