Please add a new primitive type 'Class'

Topics: Language Specification
Oct 3, 2012 at 6:23 PM

For example:

class Greeter { ... }

// only classes can be assigned to variables or members of type 'Class':
var c : Class = Greeter;

// this would trigger a compile time error: 
var c2 : Class = 123;

// only variables or members of type 'Class' can be instantiated:
var x = new c();

// nice to have: typeof() on a  variables or members of type 'Class' return the class name:
var s = typeof( c );

Thanks!

 

Coordinator
Oct 3, 2012 at 6:55 PM

The typeof piece won't be possible as it's a runtime thing and TypeScript's types do not persist at runtime. The good news is that what you want is already possible! A class in TypeScript is a combination of two things: A construct signature and a brand. Brands are unique to each class, so you don't care about those. Your question then boils down to: what type will be assignment compatible with every class? Consider this:

interface Class {
    new (... args): any;
}

This interface will be assignment compatible with any class because all classes will have a construct signature with one or more arguments that returns something assignment compatible with any. You can limit this further depending on your use case.

Oct 3, 2012 at 7:20 PM

But then all of my classes would have to derive from Class, correct?

interface Class {
    new (... args): any;
}

class Greeter implements Class { ... }

That would also mean that every class would have to implement the new operator, i.e:

class Greeter implements Class {
  new (... args ) : any {
    return new Greeter();
  }
}

correct?

Coordinator
Oct 3, 2012 at 7:28 PM

That is not the case :) The new (): any; signature is a special signature called a construct signature. It specifies the signature of a constructor when calling it with new. Secondly, TypeScript is structurally typed. The only thing you need to be assignment compatible with the interface Class is an object that has a construct signature. All classes will have a construct signature. Try it out :)

Oct 3, 2012 at 7:34 PM

Hmm, I tried this but it gives me syntax errors:

interface Class {
    new (args:any): any;
}

class Animal implements Class {
    constructor(public name) { }
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

The syntax error is on the 'class Animal' line. It says:

Class 'Animal' declares interface 'Class' but does not implement it: 
Type 'Class' requires a construct signature, but Type 'Animal' lacks one new(name: any) => Animal

Did I misunderstand your suggestion?

BTW, this gave me a syntax error:

new (... args): any;

Cheers,

- Bernd

Coordinator
Oct 3, 2012 at 7:37 PM
Edited Oct 3, 2012 at 7:37 PM

Your classes do not implement that interface, it describes the class itself. Interfaces that classes implement describe the shape of instances of that class, whereas I believe you are asking how to identify the constructors themselves. Remove the implements clause and you should be good. Then you can use the type Class for any vars or parameters you want to be classes.

Oct 3, 2012 at 8:15 PM
Edited Oct 3, 2012 at 8:15 PM

yes, that worked!

 

var SnakeClass : Class = Snake;
var sam = new SnakeClass("Sammy the Python");

 

What's really impressive is that the type inference engine detects signature violations.

This give me an error, which it should but many other languages don't:

 

// flags: "Supplied parameters do not match any signature of call target Class"
var sam = new SnakeClass();

 

Nice work!

- Bernd

Dec 7, 2012 at 4:51 AM

I think the interface you are really looking for is this:

interface Class {
    new (): any;
    new (...params: any[]): any;
}
This way you aren't forcing all classes to have a constructor signature which requires a parameter.