11

In TypeScript I can define the type of a variable as the type of a class. For example:

class MyClass { ... }

let myVar: typeof MyClass = MyClass;

Now I want to use this with a generic class, something like this:

class MyManager<T> {
    constructor(cls: typeof T) { ... }
    /* some other methods, which uses instances of T */
}

let test = new MyManager(MyClass); /* <MyClass> should be implied by the parameter */

So, I want to give my manager class another class (its constructor), because the manager needs to retreive static information associated with the class.

When compiling my code, it says that it cannot find name 'T', where my constructor is.

Any idea how to solve it?

Simon
  • 683
  • 3
  • 7
  • 18

1 Answers1

19

You can use this type of constructors: { new (): ClassType }.

class MyManager<T> {
    private cls: { new(): T };

    constructor(cls: { new(): T }) {
        this.cls = cls;
    }

    createInstance(): T {
        return new this.cls();
    }
}

class MyClass {}

let test = new MyManager(MyClass);
let a = test.createInstance();
console.log(a instanceof MyClass); // true

(code in playground)


Edit

The proper way to describe a class type in typescript is using the following:

{ new(): Class }

For example in the typescript lib.d.ts ArrayConstructor:

interface ArrayConstructor {
    new (arrayLength?: number): any[];
    new <T>(arrayLength: number): T[];
    new <T>(...items: T[]): T[];
    (arrayLength?: number): any[];
    <T>(arrayLength: number): T[];
    <T>(...items: T[]): T[];
    isArray(arg: any): arg is Array<any>;
    readonly prototype: Array<any>;
}

Here you have 3 different ctor signatures plus a bunch of static functions.
In your case you can also define it like:

interface ClassConstructor<T> {
    new(): T;
}

class MyManager<T> {
    private cls: ClassConstructor<T>;

    constructor(cls: ClassConstructor<T>) {
        this.cls = cls;
    }

    createInstance(): T {
        return new this.cls();
    }
}
CSchulz
  • 10,882
  • 11
  • 60
  • 114
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • 3
    It's not that abvious what `{ new(): T }` is about, especially because the constructor is defined as `constructor()` and one would rather expect something like just `T`, `typeof T` or whatever. – Simon Jul 11 '16 at 17:25
  • It's a standard way to define a class type/ctor, check me revised answer for more info. – Nitzan Tomer Jul 11 '16 at 17:32
  • @NitzanTomer How would you write the constructor to allow for `let test = new MyManager(Array);` ? or `...MyManager(MyClass[]);` – GFoley83 Jan 22 '17 at 06:16
  • @GFoley83 How about: `constructor(cls: MyClassConstrcutor[])` – Nitzan Tomer Jan 22 '17 at 07:44
  • @NitzanTomer What I was looking for was `constructor(cls: { new (...args: any[]): T } [])` – GFoley83 Jan 24 '17 at 06:17
  • @GFoley83 Yeah, that's what I wrote just with a type alias and without ctor arguments – Nitzan Tomer Jan 24 '17 at 07:33