如何在TypeScript中使用类键入数组?

时间:2016-06-06 08:04:54

标签: javascript typescript

我有一个应用程序通过运行方法.init(params)进行初始化,如下所示:

app.init([TopBar, StatusBar, MainArea]);

TopBarStatusBarMainArea是类,而不是类的实例。这些类中的每一个都实现相同的接口IComponent

我想在.init(params)方法中实例化传递的类中的对象,如下所示:

init(params: IComponent[]): void {
    params.map(function (component) {
        let comp = new component();
        this.components[comp.constructor.name] = comp;
    }, this);

问题在于,由于这些不是实例,因此TypeScript不知道其类型并引发错误:

  

错误TS2345:类型的参数'(typeof TopBar | typeof StatusBar |   typeof MainArea)[]'不能分配给类型的参数   'IComponent的[]'。

如何修复代码以便我可以将实现某个接口的类数组传递给方法?

6 个答案:

答案 0 :(得分:3)

working typescript playground(运行它以获得结果警报)

我们需要的是创建自定义 type InterfaceComponent 。这将是init()方法

的数组
interface IComponent { }
class TopBar    implements IComponent { }
class StatusBar implements IComponent { }
class MainArea  implements IComponent { }

// this is a type we want to be passed into INIT as an array
type InterfaceComponent = (typeof TopBar | typeof StatusBar | typeof MainArea);

class MyClass {

  components: {[key:string] : IComponent } = {};

  init(params: (InterfaceComponent)[]): void {
    params.map((component) => {
        let comp = new component();
        this.components[comp.constructor["name"]] = comp;
    }, this);
  }
}

let x = new MyClass();
x.init([TopBar, StatusBar, MainArea])

alert(JSON.stringify(x.components))

检查here

答案 1 :(得分:0)

也许您可以将comp的类型指定为InterfaceComponent

var comp: InterfaceComponent = new component();
this.components[comp.constructor.name] = comp;

答案 2 :(得分:0)

请改用工厂方法。声明有点笨拙,但这个想法有效:

interface InterfaceComponent {
    name: string;
}

class TopBar implements InterfaceComponent {
    name: string;
}

class StatusBar implements InterfaceComponent {
    name: string;
}

class MainArea implements InterfaceComponent {
    name: string;
}

interface InterfaceComponentFactory {
    create: () => InterfaceComponent;
}

function init(params: InterfaceComponentFactory[]): void {
    params.map(function (component) {
        let comp = component.create();
        this.components[comp.name] = comp;
    }, this);
}

init([{ create: () => new TopBar() }, { create: () => new StatusBar() }, { create: () => new MainArea() }]);

答案 3 :(得分:0)

Typescript支持类类型泛型(TypeScript Docs)。他们的例子是:

function create<T>(c: {new(): T; }): T {
    return new c();
}

哪个说“将{传给我的create方法的类在构造时将返回我想要的类型T”。此签名将阻止您尝试传递非T类型的任何类类型。

这很接近我们想要的,我们只需要对其进行调整,使其成为您的IComponent的一系列商品即可。

public init(components: {new(): IComponent;}[]): void {
    // at this point our `components` variable is a collection of
    // classes that implement IComponent

    // for example, we can just new up the first one;
    var firstComponent = new components[0]();
}, this);

有了方法签名,我们现在可以像使用它一样

app.init([TopBar, StatusBar, MainArea]);

我们在其中传递实现IComponent的类型数组

答案 4 :(得分:0)

即使这是一个古老的问题:这是您的操作方式:

interface IComponent { something(): void; }
class TopBar implements IComponent { something() { console.log('in TopBar'); }}
class StatusBar implements IComponent { something() { console.log('in StatusBar'); }}
class MainArea implements IComponent { something() { console.log('in MainArea'); }}

interface ComponentClass {
    new(): IComponent;
}

const components: { [name: string]: IComponent } = {};

function init(params: ComponentClass[]) {
    params.map((component) => {
        let comp = new component();
        components[component.name] = comp;
    });
}

init([TopBar, StatusBar, MainArea]);

for (const c in components) {
    console.log('Component: ' + c);
    components[c].something();
}

答案 5 :(得分:0)

对于这种情况,我发现了两种创建类型的不同方法:

// Interface style:
export default interface IConstructor<T> extends Function {
  new (...args: any[]): T;
}

// Union Type style:
export type ConstructorUnion<T> = new(...args : any[]) => T;

这就是IConstructor类型的外观:

interface IComponent { }
class TopBar implements IComponent { }
class StatusBar implements IComponent { }
class MainArea { }

class App {
  public components: { [key: string]: IComponent } = {};

  public init(params: IConstructor<IComponent>[]): void {
    params.forEach((Component: IConstructor<IComponent>) => {
      const comp: IComponent = new Component();

      this.components[comp.constructor.name] = comp;
    });
  }
}

const app = new App();

app.init([TopBar, StatusBar, MainArea]);

console.clear();
console.log(app);

这是代码: https://stackblitz.com/edit/how-to-type-an-array-with-classes-in-typescript?file=index.ts