繁体   English   中英

在Typescript中使用带有联合类型的Mixins

[英]Use Mixins with union types in Typescript

我有一个简单的系统,在该系统中,可以通过从单独的基类继承它们,然后在另一个类中混合每个类来生成类。 这是我的混合类:

type Constructor<T = {}> = new (...args: any[]) => T;

/**
 * Based on the Mixin idea explained here:
 * https://mariusschulz.com/blog/typescript-2-2-mixin-classes
 *
 * @param base
 * @constructor
 */
export function EntityServices<TBase extends Constructor>(base: TBase) {
  return class extends base {
    private _components = {};

    public addComponent(component: Component) {
      throw new Error('Not implemented');
    }

    public removeComponent(component: Component) {
      throw new Error('Not implemented');
    }
  };
}

这个mixin在另一个模块中用于创建几个类,如下所示:

class ContainerEntityBase extends Phaser.GameObjects.Container {}
class ImageEntityBase extends Phaser.GameObjects.Image {}
class SpriteEntityBase extends Phaser.GameObjects.Sprite {}
class TextEntityBase extends Phaser.GameObjects.Text {}

export const ContainerEntity = EntityServices(ContainerEntityBase);
export const ImageEntity = EntityServices(ImageEntityBase);
export const SpriteEntity = EntityServices(SpriteEntityBase);
export const TextEntity = EntityServices(TextEntityBase);

// Type definitions have to be exported separately so that they can be used as types elsewhere, not as values
// Same name with values (classes) does not matter since TS stores values and types into separate
// namespaces.
export type ContainerEntity = InstanceType<typeof ContainerEntity>;
export type ImageEntity = InstanceType<typeof ImageEntity>;
export type SpriteEntity = InstanceType<typeof SpriteEntity>;
export type TextEntity = InstanceType<typeof TextEntity>;
export type BlackbirdEntity = ContainerEntity | ImageEntity | SpriteEntity | TextEntity;

如您所见,我已经使用一个额外的联合类型BlackBirdEntity导出了实际创建的类及其类型。 有时我会使用可能是任何已生成类型的变量,因为在这些情况下,这些实例是通过其常见的混合接口操作的。

接下来,我有以下使用联合类型的简单定义:

import { Component } from '../core/Component';
import { BlackbirdEntity } from '../core/entities';

export interface IEntityDefinition {
  name: string;
  components: Component[];
  type: BlackbirdEntity;
}

我使用它来创建一个实现上述接口的对象:

import { SpriteEntity } from '../core/entities';
import { IEntityDefinition } from './EntityDefinition';

const clickableEntity: IEntityDefinition = {
  components: [],
  name: 'Clickable',
  type: SpriteEntity
};

但是,这给我在IDE上突出显示SpriteEntity的以下错误:

TS2322: Type '{ new (...args: any[]): EntityServices<typeof SpriteEntityBase>.(Anonymous class); prototype: EntityServices<any>.(Anonymous class); } & typeof SpriteEntityBase' is not assignable to type 'BlackbirdEntity'.   Type '{ new (...args: any[]): EntityServices<typeof SpriteEntityBase>.(Anonymous class); prototype: EntityServices<any>.(Anonymous class); } & typeof SpriteEntityBase' is not assignable to type 'EntityServices<typeof TextEntityBase>.(Anonymous class) & TextEntityBase'.     Type '{ new (...args: any[]): EntityServices<typeof SpriteEntityBase>.(Anonymous class); prototype: EntityServices<any>.(Anonymous class); } & typeof SpriteEntityBase' is missing the following properties from type 'EntityServices<typeof TextEntityBase>.(Anonymous class)': _components, addComponent, removeComponent

为什么? 以及如何解决这个问题? 该错误似乎表明SpriteEntity缺少TextEntity的父类中实际上存在的属性。 那么,即使父母的定义不同,有什么办法告诉编译器这种类型应该没问题吗?

您的问题是IEntityDefinition希望其type属性是BlackbirdEntity实例 ,而不是BlackbirdEntity构造函数 您可能会感到困惑,因为对于一个class ,构造函数通常与实例类型共享一个名称,即使它们不是同一对象

无论如何,您已经有了一个Constructor<T>类型别名,所以让我们使用它:

export interface IEntityDefinition {
  name: string;
  components: Component[];
  type: Constructor<BlackbirdEntity>; // you want a constructor, not an instance here
}

这应该使您的clickableEntity变量初始化可以正确编译。

希望能有所帮助; 祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM