Feature request: Classes themself as types

Topics: Language Specification
Nov 17, 2012 at 4:26 PM
Edited Nov 18, 2012 at 8:07 PM

It would be nice to have classes (not instances) themself as types like in Java.

This is already possible in raw JS: code & live example: http://jsbin.com/iyenin/1/edit 

Here is what I dream of:

 

class Handler {
}

class DerivedHandler {
}

function createHandler(handler: Class<Handler>) {
  var obj = new handler();
  // or handler.createInstance()

  return obj;
}

// Both should work
createHandler(Handler);
createHandler(DerivedHandler);


// The same could also be implemented for interfaces
// where only classes implementing it would be allowed
interface IHandler {
}

class SpecialHandler implements IHandler {
}

function createHandler(handler: Class<IHandler>) {
  // same as above
}

// Throws exception
createHandler(IHandler);
// Should work
createHandler(SpecialHandler);

 

Edit: There is already an issue entitled "Passing class type as parameter" which describes the same idea. But I leave this thread opened because class types implementing interfaces are also covered here.

Nov 18, 2012 at 5:12 PM

I believe a class can be passed to a function (on run-time you will actually pass a variable with the same name), you can just not declared a class as parameter type of the function parameters, so it has to be any (or at least I have no idea how to declare that).

The following should work:

class Test {
    hello() { console.log("hello"); }
}

function createHandler(p) : Test  {
     var x = new p();
     return x
}

var t = createHandler(Test);
t.hello();

// Peter

Nov 18, 2012 at 8:07 PM

Hi Peter,

that's exactly the point: invent a type for it.

If you pass the class itself in pure JavaScript, you're actually passing the function (pointer) of the constructor.
This can already be expressed in TypeScript:

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

function sample(ClassType: new (name: string) => MyClass) {
    var obj = new ClassType("hello");
}
But that's just too complicated and redundant! 

Nov 19, 2012 at 6:25 AM

Great answer!

The only thing I don't get is what's complicated or redundant? It's about the same number of characters, but you can additionally specify the arguments. 

Coordinator
Nov 19, 2012 at 7:54 AM

There are a few topics touched on here:

1) Types for constructors:  A class definition does create a class side type for the constructor object, which combines both the 'new' signature and the statics defined on the class.   However, there is no name given to this.  As noted above, some syntax to recover this from the class name itself, like "class<MyClass>" or "MyClass.static" or "typeof<MyClass>" are being considered.

2) Class-side inheritance:  Are statics of a class inherited by subclasses, therefor ensuring that subclass constructors are themselves subclasses of base class constructors.  Currently they are not in TypeScript, but we expect to change this to match the ES6 class proposal. 

3) Passing just the 'new' signature as the parameter type:  As noted in the MyClass/sample example above, it is possible to use 'new' signatures to cover some of the use cases already.

Nov 23, 2012 at 12:32 PM

Hi mihailik and lukeh!

Sorry for the late response.

@lukeh:

2.) I wondered why static class members aren't accessible in derived classes. That should definitely be implemented!

@lukeh third point and @mihailik:

Imagine you're using an external class. What happens if you (or someone other) change the constructor or at least one 'version' (overloading) of it? You have to change the new function pointer (e.g. in your function), too!

Another point is that the IntelliSense displays only the constructor you've declared as the 'class type'. What about classes having multiple constructors?

Nov 23, 2012 at 3:30 PM

 

If your function indeed uses that constructor, you will have to change its code, whether your proposed syntax exists or you use the constructor signature.

That also highlights another point: derived classes can overload constructors. How are you going to verify signatures in that case? If you only account for argument types in resolution/binding (same as in method resolution), you make people to get in trouble when they define a new constructor in a derived class that happens to have the same types of arguments, but new meaning. 

Apr 4, 2013 at 2:53 AM
Any updates on this?
Aug 1, 2013 at 5:38 PM
I have the same problem, will this feature be implemented?
Developer
Aug 2, 2013 at 11:52 PM
The following will work in the upcoming 0.9.1 release:
class Handler {
}

class DerivedHandler {
}

function createHandler(handler: typeof Handler) {
    var obj = new handler();
    return obj;
}

createHandler(Handler);
createHandler(DerivedHandler);
When used in a type position, the 'typeof' operator obtains the type of an expression, which in this case is the type of the Handler constructor function.
Oct 5, 2013 at 3:15 AM
Edited Oct 5, 2013 at 3:36 AM
Note: Using "typeof" in this context doesn't allow for inheritance. If you pass a derived type, it will error out.
Developer
Oct 7, 2013 at 5:32 PM
Can you clarify which example you mean? Anders' example looks to be working as intended with derived classes (ie no error).
Oct 7, 2013 at 6:18 PM