microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.83k stars 12.46k forks source link

ConstructorOf<T> wrapper to declare type of constructor of type parameter #26990

Open championswimmer opened 6 years ago

championswimmer commented 6 years ago

so if I have

class MyClass {
}

Then the type of MyClass.prototype is MyClass And the type of MyClass is typeof MyClass

If I want these two functions

function takesPrototype(p: MyClass) { /* ... */ }
function takesClass(p: typeof MyClass) { /* ... */ }

I can call them as

takesPrototype(MyClass.prototype)
takesClass(MyClass)

But what if MyClass was defined as a type parameter. For example if I want to have a function that of this type -

const mod = getModule(ModuleClass)
// mod should be of type ModuleClass

I would like to define this as such

function getModule<M extends Module>(moduleClass: typeof M): M {
 // something like a getInstance() pattern
}

The problem with this is typeof M will complain that I am trying to use M as a value while it is a type.

So I suggest a type wrapper of this type

type ConstructorOf<C> = { new( ...args: any[] ): C }

Now I can define my function as such

function getModule<M extends Module>(moduleClass: ConstructorOf<M>): M {
 // something like a getInstance() pattern
}
RyanCavanaugh commented 6 years ago

Seems like you solved your problem 😉

Is this a suggestion to add that type to the global scope?

championswimmer commented 6 years ago

Is this a suggestion to add that type to the global scope?

Yes it is! Would be useful lot of places :)

alecgibson commented 3 years ago

This would definitely be a nice global generic to have access to!

My one comment is that it should probably be called Constructor<T>, since <T> is sort of read as "of 'T'" already.

For example:

Zamralik commented 3 years ago

Any news on Constructor<T> being added natively in TypeScript ?

Doesn't seem like it would be difficult nor is there people against it.

kungfooman commented 2 years ago

I ran into this issue as well, I thought something like that should exist natively already, until I found this issue. My use case is:

export type Constructor<C> = { new (...args: any[]): C; };

export function newArray<T>(constructor: Constructor<T>, n: number): T[] {
  return doTimes(()=>new constructor, n);
}

To simply generate an array of any kind of class:

  var quats = newArray(pc.Quat, 10);
  // quats is now: (10) [Quat, Quat, Quat, Quat, Quat, Quat, Quat, Quat, Quat, Quat]

Maybe I'm missing something and there is already a shorter way to create an array of n objects?

SmashingQuasar commented 2 years ago

It would be cool to have this, it's really annoying to have to define it ourselves. It would probably take less than an hour to implement on TypeScript's end.