You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current type of Example.constructor is Function, but I feel that it should be typeof Example instead. The use case for this is as follows:
I'd like to reference the current value of an overridden static property on the current class.
In TypeScript v1.5-beta, doing this requires:
classExample{staticsomeProperty="Hello, world!";constructor(){// Output overloaded value of someProperty, if it is overloaded.console.log((<typeofExample>this.constructor).someProperty);}}classSubExample{staticsomeProperty="Overloaded! Hello world!";someMethod(){console.log((<typeofSubExample>this.constructor).someProperty);}}
After this proposal, the above block could be shortened to:
classExample{staticsomeProperty="Hello, world!";constructor(){// Output overloaded value of someProperty, if it is overloaded.console.log(this.constructor.someProperty);}}classSubExample{staticsomeProperty="Overloaded! Hello world!";someMethod(){console.log(this.constructor.someProperty);}}
Also, for clarity, as discussed in #4356 it is logical based on the ES specification to strongly type .constructor property of an instance and the following is essentially equivalent valid ways of creating instances:
Reacted by acrazing, Daniel, Brian M Hunt, Abhishek Datta, Artur Klesun, Ivan Pesochenko, mdonges, Fahdil Hazain, Anatoly Weinstein, Aleksey Mihailiuk and 1 more
I spoke with Anders Hejlsberg (@ahejlsberg) about this - we could type constructor fairly well just with a change to our lib.d.ts now that we have this types (in theory):
But! There are two issues - we don't instantiate this types on apparent type members (as in, anything on object) correctly right now, and there would be a performance impact in making every object have a this typed member (it's constructor member). Additionally, this method doesn't capture the arguments of the constructor of the class (or its static members), so it could stand to be improved.
Reacted by Ionel lupu, Matheus Placido Ferreira Gomes and fjodor-rybakov
Additionally, this method doesn't capture the arguments of the constructor of the class (or its static members),
This was a dealbreaker for us since it wouldn't even address the problem in the OP. Wiring it up in the compiler the same way we do prototype seems necessary.
This is currently allowed, but with this issue fixed it should produce an error that the literal is missing the constructor property? If it didn't produce an error, then it would be allowed to call statics on Foo such as foo.constructor.bar() which would break if foo.constructor wasn't actually Foo.
Would this be possible to implement solely with the polymorphic this type that's a work in progress? Assuming typeof mechanics would work there as well, could the signature for Object.prototype.constructor be set to:
interfaceObject{constructor: typeofthis;}
Reacted by Daniel, Gareth Jones, Jakub Kisielewski, Kisaragi, Inadequado and Isak Wertwein
The general problem we face here is that lots of valid JavaScript code has derived constructors that aren't proper subtypes of their base constructors. In other words, the derived constructors "violate" the substitution principle on the static side of the class. For example:
classBase{constructor(){}// No parameters}classDerived{constructor(x: number,y: number){}// x and y are required parameters}varfactory: typeofBase=Derived;// Error, Derived constructor signature incompatiblevarx=newfactory();
If we were to add a strongly typed constructor property to every class, then it would become an error to declare the Derived class above (we'd get the same error for the constructor property that we get for the factory variable above). Effectively we'd require all derived classes to have constructors that are compatible with (i.e. substitutable for) the base constructor. That's simply not feasible, not to mention that it would be a massive breaking change.
In cases where you do want substitutability you can manually declare a "constructor" property. There's an example here. I'm not sure we can do much better than that.
Reacted by Frederic Barthelemy, c69, Daniel, Uladzimir Dziomin, s4m0r4m4, SPGoding, James Bromwell, sth, ExE Boss, David B Ludlow and 3 more
Could someone please add it to TS Milestones for one of the upcoming versions
The issue is open for 9 years. And it deserves being addressed. Brief Stackoverflow review shows devs even started using ClassName.method notation instead of this.constructor.method thus bringing Divergent Change code smell into their projects to simply satisfy the typing
The solution above by @jwbth seems the most clear and concise.
It is just one line of code at the top. Not a big deal.
But it still has to be added and class name still has to be provided in two distinct places. If someone accidentally forgets to change one of them while changing the other, this can lead to a very pleasant debugging experience.
Reacted by Maciej Holyszko, Balearica, Willster Johnson, esheyw, Eugeny Mukhanov, Noam Anisfeld, György K. Farkas, d-goog, Ben van Enckevort, jdittrich and 8 more
This works for me as well, I put this to the superset class and subclasses inherit this correctly with constructor being a type of the according subset class.
class C {
- declare ['constructor']: typeof C;+ declare ["constructor"]: typeof this;
}
Unfortunately, it doesn't work with Object interface :(
Because Object is not actually being treated as a super class of other classes by default.
It confused me for a moment, but this and typeof this both yield the same type here: the instance type. typeof this does not refer to the constructor inside the class body.
That’s still incorrect, the value of C.constructor is globalThis.Function; it’s new C().constructor and C.prototype.constructor that refer to the class C.
Constructor signatures and call signatures cannot be inherited like other members, static or otherwise.
It is impossible to know what arguments are required for new this.constructor(...) because it could be any subclass, and there's no way to enforce a particular constructor signature on a subclass.
The work around to this is a static factory function
This isn't a great solution since nothing is forcing subclasses to implement createWithXy, nor does it necessarily make sense for a subclass to even have such a constructor.
Basically anything involving invoking a constructor cannot be reliably typed except for concretely.
There are certainly cases where having a semantic factory function is useful (eg. new MyArray().filter()) but even then its easy to imagine situations where a subclass won't have a logically correct constructor to use.
So I think we accept that new this.constructor is a bad idea unless you want confusion and type errors.
That said; static members are easy to reason about; B inherits static members from A and typescript is already validating static members in an intuitive way.
IMO the only correct way to type .constructor is by carrying over static members only;
This can be emulated with Pick<typeof C, keyof typeof C> which strips constructor and call signatures from a type.
classA{declare['constructor']: Pick<typeofA,keyoftypeofA>;staticfoo='bar';}classBextendsA{// for the sake of the workaround, the constructor does not need to be declared at every level}classCextendsB{declare['constructor']: Pick<typeofC,keyoftypeofC>;}constc=newC();// new c.constructor(); errorconsole.log(c.constructor.foo);
I hope that it shouldn't be too hard to have that kind of signature dynamically defined by the language service..
At the very least, typescript is able to provide accurate intellisense about static members, given a concrete class.
Static members don't adhere to the same constraints as instance members. Defining an interface dictates what an instance method with that name should do, and superclasses allow you to provide default functionality to fulfill those contracts. Static methods do have inheritance but don't provide the same kind of contract adherence; You can't define static members in an interface nor create abstract static members.
I think the problem that most people are trying to solve with T.constructor is to get access to a T factory for some purpose. We're looking for something like this as a well-known way to construct T
I use TS only for type augmentation and I'd love for this to be implemented, kinda tired of writing the following for every single class:
interfaceMyClass{constructor: typeofMyClass;}
Even if current behaviour might be desired by someone (who, really?), having an option that you can enable in tsconfig for assuming actual class type instead of some unrelated anonymous function would be incredibly useful, if it can't be made default behaviour.
Though also, even if someone makes their subclass demolish the typing of the parent class as was mentioned above, this kind of type inference would still be much more accurate than the current anonymous function assumption. Such masking of parent class functionality would be breaking typing anyway, so I don't think it matters as base behaviour.
Anyway, this typing change would be a Massive QoL improvement for me, please implement it.
Reacted by Luiz Américo, Valery Zinchenko, hasezoey, 47PADO47, McGreger and Alexander Spirgel
Activity
kitsonk commentedon Sep 29, 2015
Also, for clarity, as discussed in #4356 it is logical based on the ES specification to strongly type
.constructorproperty of an instance and the following is essentially equivalent valid ways of creating instances:RyanCavanaugh commentedon Oct 5, 2015
Accepting PRs for this. Anyone interested? 😄
weswigham commentedon Oct 5, 2015
I spoke with Anders Hejlsberg (@ahejlsberg) about this - we could type constructor fairly well just with a change to our lib.d.ts now that we have
thistypes (in theory):But! There are two issues - we don't instantiate this types on apparent type members (as in, anything on object) correctly right now, and there would be a performance impact in making every object have a this typed member (it's constructor member). Additionally, this method doesn't capture the arguments of the constructor of the class (or its static members), so it could stand to be improved.
RyanCavanaugh commentedon Oct 5, 2015
This was a dealbreaker for us since it wouldn't even address the problem in the OP. Wiring it up in the compiler the same way we do
prototypeseems necessary.jbondc commentedon Oct 20, 2015
Can take a look, does
jbondc commentedon Oct 20, 2015
Nevermind, it's a bit more involved then I thought. Attempt here in case helpful:
master...jbondc:this.constructor
Think proper way involves changing
ConstructorKeywordin getSymbolAtLocation()Arnavion commentedon Dec 6, 2015
As I mentioned in #5933, will this not be a breaking change for assigning object literals to class types?
This is currently allowed, but with this issue fixed it should produce an error that the literal is missing the
constructorproperty? If it didn't produce an error, then it would be allowed to call statics on Foo such asfoo.constructor.bar()which would break iffoo.constructorwasn't actually Foo.LPGhatguy commentedon Dec 9, 2015
Would this be possible to implement solely with the polymorphic
thistype that's a work in progress? Assumingtypeofmechanics would work there as well, could the signature forObject.prototype.constructorbe set to:ahejlsberg commentedon Dec 9, 2015
The general problem we face here is that lots of valid JavaScript code has derived constructors that aren't proper subtypes of their base constructors. In other words, the derived constructors "violate" the substitution principle on the static side of the class. For example:
If we were to add a strongly typed
constructorproperty to every class, then it would become an error to declare theDerivedclass above (we'd get the same error for theconstructorproperty that we get for thefactoryvariable above). Effectively we'd require all derived classes to have constructors that are compatible with (i.e. substitutable for) the base constructor. That's simply not feasible, not to mention that it would be a massive breaking change.In cases where you do want substitutability you can manually declare a
"constructor"property. There's an example here. I'm not sure we can do much better than that.89 remaining items
thodnev commentedon Oct 16, 2024
Could someone please add it to TS Milestones for one of the upcoming versions
The issue is open for 9 years. And it deserves being addressed. Brief Stackoverflow review shows devs even started using
ClassName.methodnotation instead ofthis.constructor.methodthus bringing Divergent Change code smell into their projects to simply satisfy the typingThe solution above by @jwbth seems the most clear and concise.
It is just one line of code at the top. Not a big deal.
But it still has to be added and class name still has to be provided in two distinct places. If someone accidentally forgets to change one of them while changing the other, this can lead to a very pleasant debugging experience.
Ensure `addActivityItemStream()` doesn't lose `Output` vs `Error` str…
Ensure `addActivityItemStream()` doesn't lose `Output` vs `Error` str…
FrameMuse commentedon Sep 6, 2025
This works for me as well, I put this to the superset class and subclasses inherit this correctly with
constructorbeing a type of the according subset class.class C { - declare ['constructor']: typeof C; + declare ["constructor"]: typeof this; }Unfortunately, it doesn't work with
Objectinterface :(Because
Objectis not actually being treated as a super class of other classes by default.alvaro-cuesta commentedon Dec 4, 2025
Valery Zinchenko (@FrameMuse) using your
typeof thisis not working for me.Am I missing something?
Specifying each constructor works but it's easy to forget it's needed in the prototype chain.
snarbles2 commentedon Dec 4, 2025
It confused me for a moment, but
thisandtypeof thisboth yield the same type here: the instance type.typeof thisdoes not refer to the constructor inside the class body.FrameMuse commentedon Dec 4, 2025
@alvaro-cuest, snarbles2 Sorry for confusion, it should've been
It does refer to it when used in static methods.
ExE-Boss commentedon Dec 4, 2025
Valery Zinchenko (@FrameMuse)
That’s still incorrect, the value of
C.constructorisglobalThis.Function; it’snew C().constructorandC.prototype.constructorthat refer to the classC.The correct definition would be:
OldStarchy commentedon Feb 1, 2026
TL:DR; example at bottom
Constructor signatures and call signatures cannot be inherited like other members, static or otherwise.
It is impossible to know what arguments are required for
new this.constructor(...)because it could be any subclass, and there's no way to enforce a particular constructor signature on a subclass.The work around to this is a static factory function
This isn't a great solution since nothing is forcing subclasses to implement
createWithXy, nor does it necessarily make sense for a subclass to even have such a constructor.Basically anything involving invoking a constructor cannot be reliably typed except for concretely.
There are certainly cases where having a semantic factory function is useful (eg.
new MyArray().filter()) but even then its easy to imagine situations where a subclass won't have a logically correct constructor to use.So I think we accept that
new this.constructoris a bad idea unless you want confusion and type errors.That said; static members are easy to reason about;
Binherits static members fromAand typescript is already validating static members in an intuitive way.IMO the only correct way to type
.constructoris by carrying over static members only;This can be emulated with
Pick<typeof C, keyof typeof C>which strips constructor and call signatures from a type.I hope that it shouldn't be too hard to have that kind of signature dynamically defined by the language service..
ljharb commentedon Mar 10, 2026
B could also avoid inheriting static members from A (or shadow them), so it seems they're identically as difficult to reason about.
OldStarchy commentedon Mar 11, 2026
At the very least, typescript is able to provide accurate intellisense about static members, given a concrete class.
Static members don't adhere to the same constraints as instance members. Defining an interface dictates what an instance method with that name should do, and superclasses allow you to provide default functionality to fulfill those contracts. Static methods do have inheritance but don't provide the same kind of contract adherence; You can't define static members in an interface nor create abstract static members.
I think the problem that most people are trying to solve with
T.constructoris to get access to a T factory for some purpose. We're looking for something like this as a well-known way to construct Tbut trying to apply it to the static side of the class, for which the language has no support.
Though, I did just figure out this weird workaround
or more generically (playground)
mkahvi commentedon Jul 25, 2026
I use TS only for type augmentation and I'd love for this to be implemented, kinda tired of writing the following for every single class:
Even if current behaviour might be desired by someone (who, really?), having an option that you can enable in tsconfig for assuming actual class type instead of some unrelated anonymous function would be incredibly useful, if it can't be made default behaviour.
Though also, even if someone makes their subclass demolish the typing of the parent class as was mentioned above, this kind of type inference would still be much more accurate than the current anonymous function assumption. Such masking of parent class functionality would be breaking typing anyway, so I don't think it matters as base behaviour.
Anyway, this typing change would be a Massive QoL improvement for me, please implement it.
FrameMuse commentedon Jul 25, 2026
We be nice to see this in TypeScript 7.0
karl-police commentedon Aug 21, 2026
How can this be implemented or where? What powers the type solving in TypeScript?
feat(actionpack,rack): type ActionController redirect_to options and …