Repository navigation
Allow subclass constructors without super() call #7285
Description
Activity
Something similar was discussed in #5910
I know this is a very ugly solution but It works.
class MyElement extends HTMLElement { constructor() { try{ super(); }catch(e){ }finally{ return document.createElement('my-element'); } } }Or without catch
class MyElement extends HTMLElement { constructor() { try{ super(); }finally{ return document.createElement('my-element'); } } }class MyElement extends HTMLElement { constructor(element : string) { try{ super(); }finally{ return document.createElement(element); } } } alert(new MyElement("div"));Reacted by Brandon Bennettjustinfagnani commented
on Feb 29, 2016 AuthorMore actionsApparently TS's super() check isn't too robust, so I just did this:
constructor() { if (1 < 0) { // edit, this used to be 1 < 0, @xLama is right :) super(); } return document.createElement('my-element'); }
Reacted by Mendy Berger, J.C, Seph Reed and Brandon BennettI think it dows not work because it call super constructor. 1 is always greater than 0. Maybe you wanted to write 1 < 0.
I think that code will beacome deprecated when unreachable code detection improves.
this does not work
class MyElement extends HTMLElement { constructor() { if (false){ super(); } return document.createElement(); } }this it does
class MyElement extends HTMLElement { constructor() { if (0){ super(); } return document.createElement(); } }Reacted by Brandon Bennettjustinfagnani commented
on Feb 29, 2016 AuthorMore actionsOops, I meant the other way! Editing...
justinfagnani commented
on Feb 29, 2016 AuthorMore actionsJCLama (@xLama) there will always be some way to beat compile-time evaluation... it'll just get uglier over time.
- addedNeeds More InfoThe issue still hasn't been fully clarifiedThe issue still hasn't been fully clarified
on Feb 29, 2016 RyanCavanaugh commented
on Feb 29, 2016 MemberMore actionsWhat's the use of a class like this? Why not just have a factory function?
It seems crazy to have
MyElementsuch that(new MyElement()) instanceof MyElementisfalsejustinfagnani commented
on Feb 29, 2016 AuthorMore actions(new MyElement()) instanceof MyElementwill be true.document.createElement('my-element')will create an instance ofMyElement.The use, in this case, is that users want constructors, even before the built-in HTMLElement subclasses get callable constructors.
In other cases, a constructor could return a subtype, or return a cached instance.
RyanCavanaugh commented
on Feb 29, 2016 MemberMore actionsThat's not what I'm seeing in Firefox nightly -- maybe a bug on their side?
justinfagnani commented
on Feb 29, 2016 AuthorMore actionsFirefox custom element support is behind a flag. You need to enable dom.webcomponents.enabled in about:config. Or try on Chrome.
justinfagnani commented
on Feb 29, 2016 AuthorMore actionsHere's an example that works in Chrome: http://jsbin.com/xivutarobo/edit?html,console,output
With polyfills is also works on other browsers without flags.
justinfagnani commented
on Feb 29, 2016 AuthorMore actionsAdding the code here, for convenience:
class MyElement extends HTMLElement { constructor() { return document.createElement('my-element'); } createdCallback() { console.log('created my-element'); } } document.registerElement('my-element', MyElement); let el = new MyElement(); console.log(el instanceof MyElement); // true
justinfagnani commented
on Mar 4, 2016 AuthorMore actionsIs more info still needed, or was this enough?
- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptIn DiscussionNot yet reached consensusNot yet reached consensusand removedNeeds More InfoThe issue still hasn't been fully clarifiedThe issue still hasn't been fully clarified
on Mar 4, 2016 RyanCavanaugh commented
on Mar 4, 2016 MemberMore actionsI think this is enough.
For the vast majority of ES6 classes, not calling
superis a big runtime error. We'd need to figure out how to still give an error in those cases while still allowing this.justinfagnani commented
on Mar 5, 2016 AuthorMore actionsOne big sign that
superisn't necessary in the case of factory constructors is the presence of a return statement. Along with no access tothis, it might be enough.Otherwise, is there any existing warning suppression mechanism in TypeScript?
aluanhaddad commented
on Mar 11, 2016 ContributorMore actionsJustin Fagnani (@justinfagnani) If you are returning a value, not accessing
this, and not callingsuper, why is it defined as a class. What exactly do you mean by 'factory constructors'? I know what they are in dart, but in JavaScript/TypeScript people usually speak in terms of factories or constructors.justinfagnani commented
on Mar 11, 2016 AuthorMore actionsFirst, it's just valid JavaScript that can type check, so it seems like it should be supported by a superset of JavaScript. As for use cases, the custom element use case is my primary concern. HTMLElement doesn't have a callable constructor yet, so extending it requires not calling super().
As for the term "factory constructor", yes Dart explicitly has this concept, but JavaScript already supports constructors returning something other than
this. I think such constructors can reasonably be called factory constructors, instead of "constructors that return something other than this".- addedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
on Jul 5, 2016 DanielRosenwasser commented
on Jul 19, 2016 MemberMore actionsGiven that
HTMLElement's constructor never actually returns, it should actually returnnever. I'm thinking that- It should be allowed to extend something which has a construct signature of type
never. - If a construct signature of some value's type returns
never, then asupercall is not needed if extending from that value. - If there is a
super()call, it should be an error to accessthisbeforesuper(which is currently the case anyway).
Reacted by Kitson Kelly- It should be allowed to extend something which has a construct signature of type
justinfagnani commented
on Jul 19, 2016 AuthorMore actionsThe examples here, specifically regarding subclasses of
HTMLElementare a bit out of date.
HTMLElementis now specified to return a value. See: https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors in particular step 11.justinfagnani commented
on Jul 19, 2016 AuthorMore actions#7574 is much, much more important to the Custom Elements use cases now.
Is there any way this check could be put behind a flag? Being able to disregard super is incredibly useful for evolutions.
In my case I want to evolve an event, so I have something like this:
class SuperEvent extends Event { public superHeroIdentity: string; constructor(event: Event) { super(); // really trying to get rid of this line (event as any).superHeroIdentity = "Megavent"; return event; } } const boringEvent = new Event("doThing"). const superEvent = new SuperEvent(boringEvent); console.log(superEvent); // MegaventI know evolution's aren't a wide spread concept in the programming world just yet, but they're incredibly useful and one of the best things about javascript. All of this is valid javascript, so it would be really nice if typescript was capable of it as well. Also I recognize how this breaks strict typing, but I'm not really trying to compile wasm here.
Also, in this case
MyElement such that (new MyElement()) instanceof MyElement is [true]
- removedIn DiscussionNot yet reached consensusNot yet reached consensus
on Mar 7, 2019 - added a commit that references this issue
on May 9, 2023
TypeScript Version:
1.8.0
Code
Custom element classes often have constructors that just return
document.createElement(), since HTMLElement doesn't have a callable constructor, but this generates an error in TypeScript:In general, it is completely valid ES2015 to not call
super(), as long as you don't accessthis.