Func <t extends =“ =” icomponent =“”>():T [] => IComponent []-未分配给T

时间:2019-05-28 18:18:55

标签: typescript typescript-generics

我试图在打字稿中实现ECS模式,并创建了ComponentStore类,其中包含用于后续处理的实体组件。 像这样的组件:

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

但是方法setComponentgetComponents会引发错误:

  

错误:(12,11)TS2322:类型'IComponent []'无法分配给类型'T []'。    无法将类型“ IComponent”分配给类型“ T”。

     

错误:(17,5)TS2322:类型'IComponent []'无法分配给类型'T []'。    无法将类型“ IComponent”分配给类型“ T”。

我这样做的方式类似于Generics in 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;
}

我当然可以使用强制转换,但是我认为这不是个好主意。 我希望类型检测对于这些方法能够正常工作 我的目标是设置名称为EComponent的Map,该名称保留IComponent之类的一种类型IHealth的数组,然后将其传输到系统中。

2 个答案:

答案 0 :(得分:0)

我不确定您想要什么,但是也许您可以看一下这样的东西:

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

这里的想法是ComponentStoreIComponentStore已经为其应处理的IComponent实例获取了通用类型T ...

我假设IComponentEComponents是接口。我为他们提供了一个虚拟的实现。此代码应正确编译。它生成以下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。

答案 1 :(得分:0)

我更改了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) || [];
  }
}