Я пытался реализовать шаблон ECS в машинописи, и я создал класс ComponentStore, который содержит компоненты сущностей для следующей обработки. Компоненты как это:

class Health implements IComponent {
  name: EComponents = EComponents.health;
}

Но методы setComponent и getComponents выдают ошибки:

Ошибка: (12, 11) TS2322: Тип «IComponent []» не может быть назначен типу «T []». Тип «IComponent» нельзя назначить типу «T».

Ошибка: (17, 5) TS2322: Тип «IComponent []» не может быть назначен типу «T []». Тип «IComponent» нельзя назначить типу «T».

Я делаю это, как в примере в Обобщения в Typescript, но это не так работай.

class ComponentStore implements IComponentStore {
  private components: Map<EComponents, IComponent[]> = new Map();

  setComponent<T extends IComponent>( componentName: EComponents, component: IComponent): void {
    const components: T[] = this.components.get(componentName) || [];
    this.components.set(componentName, [...components, component ]);
  }

  getComponents<T extends IComponent>( componentName: EComponents): T[] {
    return this.components.get(componentName) || [];
  }
}

enum EComponents {
  health = 'health',
}

interface IComponent {
  name: Ecomponents;
}

Конечно, я могу использовать приведение, но я не думаю, что это хорошая идея. Я хотел, чтобы определение типа работало правильно для этих методов Моя цель - установить Map с некоторым именем EComponent, в котором хранится массив одного типа IComponent, например IHealth, а затем передать его в систему.

0
Diamond 28 Май 2019 в 21:18

2 ответа

Лучший ответ

Я поменял IComponent и создал из него родовой

interface IComponent<T> {
  name: EComponents;
  id: string;
}

class ComponentStore implements IComponentStore {
  private components: Map<EComponents, IComponent<any>[]> = new Map();

  setComponent<T extends IComponent<T>>( componentName: EComponents, component: IComponent<T>): void {
    const components: IComponent<T>[] = this.components.get(componentName) || [];
    this.components.set(componentName, [...components, component ]);
  }

  getComponents<T extends IComponent<T>>( componentName: EComponents): IComponent<T>[] {
    return this.components.get(componentName) || [];
  }
}
0
Diamond 6 Июн 2019 в 17:05

Я не совсем уверен, что вы хотите, но, возможно, вы можете посмотреть на что-то вроде этого:

interface EComponents {
  //...
}

interface IComponent {
  //...
}

interface IComponentStore<T extends IComponent> {
  setComponent(componentName: EComponents, component: T): void;
  getComponents(componentName: EComponents): T[];
}

class ComponentStore<T extends IComponent> implements IComponentStore<T> {
  private components = new Map<EComponents, T[]>();

  setComponent(componentName: EComponents, component: T): void {
    const components = this.components.get(componentName) || [];
    this.components.set(componentName, [...components, component ]);
  }

  getComponents(componentName: EComponents): T[] {
    return this.components.get(componentName) || [];
  }
}

Идея в том, что ComponentStore и IComponentStore уже получают универсальный тип T для экземпляров IComponent, которые он должен обрабатывать ...

Я предположил, что IComponent и EComponents являются интерфейсами. Я предоставил фиктивную реализацию для них. Этот код должен правильно скомпилироваться. Он генерирует следующий JavaScript (для ESNext):

"use strict";
class ComponentStore {
    constructor() {
        this.components = new Map();
    }
    setComponent(componentName, component) {
        const components = this.components.get(componentName) || [];
        this.components.set(componentName, [...components, component]);
    }
    getComponents(componentName) {
        return this.components.get(componentName) || [];
    }
}

Надеюсь, это поможет вам.

< Сильный > Edit:

Кстати, IComponentStore не должен быть универсальным для этого. Следующий код тоже работает:

interface EComponents {
  //...
}

interface IComponent {
  //...
}

interface IComponentStore {
  setComponent(componentName: EComponents, component: IComponent): void;
  getComponents(componentName: EComponents): IComponent[];
}

class ComponentStore<T extends IComponent> implements IComponentStore {
  private components = new Map<EComponents, T[]>();

  setComponent(componentName: EComponents, component: T): void {
    const components = this.components.get(componentName) || [];
    this.components.set(componentName, [...components, component ]);
  }

  getComponents(componentName: EComponents): T[] {
    return this.components.get(componentName) || [];
  }
}

Он генерирует тот же JavaScript.

Изменить 2

После моего последнего редактирования прошло пять дней. Но я обещал, что обновлю свой ответ еще раз, основываясь на новой информации, содержащейся в ваших комментариях. Извините за задержку.

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

enum EComponents {
  health = 'health',
  wealth = 'wealth'
}

interface IComponent {
  name: EComponents;
  value: string;
}

interface IComponentStore {
  setComponent<T extends IComponent>(component: T): void;
  getComponents<T extends IComponent>(componentName: EComponents): T[];
}

class ComponentStore implements IComponentStore {
  private components: Map<EComponents, IComponent[]> = new Map();

  setComponent<T extends IComponent>(component: T): void {
    const components: IComponent[] = this.components.get(component.name) || [];
    this.components.set(component.name, [...components, component]);
  }

  getComponents<T extends IComponent>(componentName: EComponents): T[] {
    return (this.components.get(componentName) || []) as T[];
  }
}

class Health implements IComponent {
  name: EComponents = EComponents.health;

  constructor(public value: string) {
  }
}

class Wealth implements IComponent {
  name: EComponents = EComponents.wealth;

  constructor(public value: string) {
  }
}

const store = new ComponentStore();

store.setComponent(new Health('ill'));
store.setComponent(new Health('fairly healthy'));
store.setComponent(new Health('top condition'));

store.setComponent(new Wealth('poor'));
store.setComponent(new Wealth('prosperous'));
store.setComponent(new Wealth('filthy rich'));

console.log(store.getComponents(EComponents.health));
console.log(store.getComponents(EComponents.wealth));
0
Bart Hofland 3 Июн 2019 в 13:54