Func <T расширяет IComponent> (): T [] => IComponent [] - не присваивается T - PullRequest
0 голосов
/ 28 мая 2019

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

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

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

Ошибка: (12, 11) TS2322: Тип 'IComponent []' isнельзя назначить типу '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, и затем передает его в систему.

Ответы [ 2 ]

0 голосов
/ 06 июня 2019

Я изменил 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 голосов
/ 28 мая 2019

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

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) || [];
    }
}

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

Редактировать:

Кстати, 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));
...