Passing class as parameter causes "is not newable" error

I'm trying to pass a class as a parameter to some function, that will instantiate this class and return it. Here is my code:

module A.Views {
  export class View { ... }
}

module A.App {
  export class MyApp {
    ...
    registerView(viewKlass:A.Views.View):void
    {
        var test = new viewKlass;
    } 
  }
}

When i'm trying to compile this, i'm getting:

(...): Value of type 'Views.View' is not newable.

What am I doing wrong?

If a newable type value is an object constructor how do i pass the constructor function at runtime?


Solution 1:

We need something to say typeof(MyClass) to distinguish objects from classes in function signatures.

Anyway, you can actually solve you problem by using constructor type signature. Considering this class:

class MyClass {
    constructor (private name: string) {
    }
}

To pass that class as a type that you can then instantiate in a function, you actually have to duplicate the class constructor signature like this:

function sample(MyClass: new (name: string) => MyClass) {
    var obj = new MyClass("hello");
}

EDIT : There is a simple solution found on codeplex:

You have to create an interface for your class like this:

interface IMyClass {
    new (name: string): MyClass;
}

Then, use it in your function signature:

function sample(MyClass: IMyClass) {
    var obj = new MyClass("hello");
}

Solution 2:

To supplement the other answers; I have a utility type I keep around to ensure a generic parameter/field is a class/newable:

/* new T() */
export type Newable<T> = { new (...args: any[]): T; };

You can then ensure you get a class constructor:

class MyApp<TViewBase>
{
  register<TView extends TViewBase>(view: Newable<TView>) { 
  }
}

the Newable<T> approach works where typeof T --where T is a generic type-- does not.

For example: register<T extends TViewBase>(view: typeof T) results in the following error:

[ts] 'T' only refers to a type, but is being used as a value here.

Solution 3:

Try this:

export class MyApp {
    registerView(viewKlass: typeof A.Views.View): void {
        var test = new viewKlass();
    } 
}