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
{{ message }}
Repository navigation
super() with an options object (possibly a FAQ) #7644
(Apologies if this is known, but I search a bunch of places and didn't find anything.)
Is there a good way to deal with a constructor of a derived class that is getting an options kind of value that needs to be merged with a defaults value? I started with something like this:
export class Foo extends Bar {
...
private options: any = {};
...
constructor(x: Something, y: SomethingElse, options: any = {}) {
this.options = $.extend({}, defaults, options);
super(this.options.blah);
...
}
}
... but that still hits the error that the super() call needs to be first.
I've worked around a similar issue (needed to swap derived class constructor parameters before calling base class constructor to maintain backward compatibility) by abusing an IIFE as the super() parameter.
Edit: Since you're always assigning to this.options in the constructor, you can remove the initialiazer for the class member options. Then the first alternative I gave will also compile.
The problem is that all of these are ugly hacks, and it looks very strange that the usual facility for keyword arguments thing cannot work in such constructors.
BTW, I couldn't get your hack to work, perhaps the TS version I'm using is too old. But if we're talking about such workarounds, then here's another ugly hack that works around it (based on an old Lisp hack of abusing optional arguments similarly):
In any case, I find it surprising that there is no proper way to do this, given that it's a common enough JS pattern that it's been embraced as the proper way to do keyword arguments.
Not 100% sure what the best approach is, but since this is really an ES6 thing (must invoke super before using this) you might find some good answers on Stack Overflow by just posting under the [javascript] tag
Ryan Cavanaugh (@RyanCavanaugh), so I looked at it more, and I still think that there's a specific TS issue here. I can understand where the ES6 restriction is coming from, but trying it via TS still seem weird.
I dug some more, and it looks like usually initialized properties are handled after the super() call, except when there is some expression before the super, and even when that expression doesn't try to access this. Here's an example that shows this:
class Bar { private x; constructor(x: any) { this.x = x; }}
class Foo extends Bar {
private mu = 9999;
private options;
constructor(x: string, y: number, options: any = {}) {
// options = [123, options];
super(options.blah);
this.options = options;
}
}
This works fine, and the output has this.mu = 9999; after the super call. Now uncomment the options setting line, and for some reason the mu initialization moves up to before the the super call. Is that intentional?
As a side note, I also think that it'll be good to add it to your FAQ since people will probably do what I did, and look for the error message. So a quick entry saying that it's an ES6 issue would be better than nothing...
Since you're always assigning to this.options in the constructor, you can remove the initialiazer for the class member options. Then the first alternative I gave will also compile.
Arnav Singh (@Arnavion), see the example in my reply to Ryan Cavanaugh (@RyanCavanaugh) above: the problem is that if there is any initialized member TS does the assignment before the super call. In my case it's obviously ok to drop the initialization of options, but there are other members that are initialized.
Activity
Arnavion commentedon Mar 22, 2016
The assignment to
this.optionsbefore callingsuper()is illegal per ES6 semantics, so that can't be done anyway.You could assign to a temporary (eg back to
options), do thesuper()call, then assignoptionstothis.options... but that still hits the error that the
super()call needs to be first.I've worked around a similar issue (needed to swap derived class constructor parameters before calling base class constructor to maintain backward compatibility) by abusing an IIFE as the
super()parameter.Edit: Since you're always assigning to
this.optionsin the constructor, you can remove the initialiazer for the class memberoptions. Then the first alternative I gave will also compile.elibarzilay commentedon Mar 23, 2016
The problem is that all of these are ugly hacks, and it looks very strange that the usual facility for keyword arguments thing cannot work in such constructors.
BTW, I couldn't get your hack to work, perhaps the TS version I'm using is too old. But if we're talking about such workarounds, then here's another ugly hack that works around it (based on an old Lisp hack of abusing optional arguments similarly):
In any case, I find it surprising that there is no proper way to do this, given that it's a common enough JS pattern that it's been embraced as the proper way to do keyword arguments.
RyanCavanaugh commentedon Mar 23, 2016
Not 100% sure what the best approach is, but since this is really an ES6 thing (must invoke
superbefore usingthis) you might find some good answers on Stack Overflow by just posting under the [javascript] tagelibarzilay commentedon Mar 23, 2016
Ryan Cavanaugh (@RyanCavanaugh), so I looked at it more, and I still think that there's a specific TS issue here. I can understand where the ES6 restriction is coming from, but trying it via TS still seem weird.
I dug some more, and it looks like usually initialized properties are handled after the
super()call, except when there is some expression before thesuper, and even when that expression doesn't try to accessthis. Here's an example that shows this:This works fine, and the output has
this.mu = 9999;after thesupercall. Now uncomment theoptionssetting line, and for some reason themuinitialization moves up to before the thesupercall. Is that intentional?As a side note, I also think that it'll be good to add it to your FAQ since people will probably do what I did, and look for the error message. So a quick entry saying that it's an ES6 issue would be better than nothing...
Arnavion commentedon Mar 24, 2016
Eli Barzilay (@elibarzilay) I did say
elibarzilay commentedon Mar 24, 2016
Arnav Singh (@Arnavion), see the example in my reply to Ryan Cavanaugh (@RyanCavanaugh) above: the problem is that if there is any initialized member TS does the assignment before the
supercall. In my case it's obviously ok to drop the initialization ofoptions, but there are other members that are initialized.