Description
Right now the compiler always checks if a super call is made, it is indeed the first statement in the constructor. This is even true if the statements before the super call don’t access anything of the object just being constructed.
It would be nice to not allow access to object variables and methods but allow for other kind of statements. For example the following gives an warning:
constructor(name) {
var filePath = someGlobalFunction(name);
super(filePath);
}
while the following is ok:
constructor(name) {
super(someGlobalFunction(name));
}
Of course the sequence of commands in the above two example is the same (and one might argue that the second example is the less maintainable/debuggable code). So would be great if the first example wouldn't throw a compiler warning.
I guess the tricky part is to determine which statements are ok to be used before the super call. But I would assume if the statements don’t include this or super keywords, they should be ok.
Activity
jednano commentedon Oct 23, 2014
Totally 100% agree! I ran into some issues with this in my TypeScript code and I would have loved to have had this feature. This is the first language I've used where it forces you to call the
super
function at the beginning of the constructor. This is not always ideal.Unless it's a code smell of which I was not aware. In which case, please provide information as to how it's a code smell or bad practice to do otherwise.
RyanCavanaugh commentedon Oct 23, 2014
C#, C++, and Java enforce this rule - it's not an uncommon one.
Basically there's nothing valid you can do that must come before the base class super call. It's sometimes annoying in the case where you'd like to use the result of a function call more than once, but it's important to not try to use the base class before it's been initialized.
electricessence commentedon Oct 23, 2014
Actually, it doesn't force you to have it first all the time.
If you do not initialize values outside the constructor or provide private/public parameters, then it doesn't complain. There are ways around most of it, but I really think the solution is that the compiler adapt to certain situations. Like for example, I think the private/public parameters blocking you from having the super call later is pretty silly. Those values should simply be initialized before the super call and that's that. But I do agree that if you initialize a variable outside the constructor, you could be asking for trouble.
Works:
Doesn't Work:
This example it makes sense to fail because there are too many conditions to check where there might be problems since blah actually get's initialized after the constructor.
Doesn't Work:
This sample should be able to work and the compiler should go ahead and initialize the blah value before the constructor code begins.
danquirk commentedon Oct 23, 2014
The exact rules from the spec explaining the above behavior (8.3.2):
As Ryan said, for the cases that are disallowed there are workarounds, because for the most part you can't do many safe things this way.
You mean like this?
jbaron commentedon Oct 23, 2014
Agree that most problems come when using initialized properties. If you would indeed avoid them, more things are allowed (I guess I just a fan of intializing properties early on, since it saves some typing and for feels a bit more natural).
But I would also have expected that a simple rule like no access to this before the super call would be easy to implement and understand, while provide still lots of posiibilities to do stuff before the super call.
So the following would work (since there is no reference to this before the super call):
At the end there are ways around it, so no deal breaker. Just after using TypeScript extensively noticed that the current implemented rule is more often than not a (minor) annoyance.
danquirk commentedon Oct 23, 2014
That case is the same as the parameter property one. Replace the definition of my
Derived
example with your code and you'll see the same bad behavior where Derived's constructor initialization work is overwritten by something in the base class constructor..jbaron commentedon Oct 23, 2014
Not sure I get that. How can a local scoped variable (var somethingbeforetheconstructor = 10) ever be overwritten by something in the base class constructor? Am I missing something?
My typical use case would be something like this (just to demonstrate it with an example that in my endeavors with TypeScript regular occurs):
Ofcourse my current workaround would be to invoke the super call as follows to avoid the compiler complaints:
RyanCavanaugh commentedon Oct 24, 2014
We'd still have to do fairly extensive analysis to determine whether or not you were indirectly using
this
in an arbitrary expression. Other languages do fine with this restriction and we think it's one that makes a lot of sense.pdfernhout commentedon Apr 23, 2016
I suggest this issue be reopened based on discussion here: microsoft/TypeScript-Handbook#214
While it is reasonable in TypeScript to not permit
this
to be referenced in a constructor before calling super when there are initialized properties or constructor parameter properties, broader restrictions on calling other code don't seem that helpful and can be worked around anyway, like by function calls inside a super call such assuper(logThisName(name));
where the called function refers tothis
. As show by an example in the above linked discussion, ES6 permits other code in a constructor before a super call (although accessingthis
in called code would generate a runtime error before super was called), so in that sense, TypeScript is being more strict than what ES6 permits.pdfernhout commentedon Apr 24, 2016
As requested by @mhegazy, I have made a new issue for a fresh discussion on this topic (issue #8277).
Breaking change !!!