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
Node.parentElement should be Element, not HTMLElement #4689
The declaration of the parentElement property on the Node interface in lib.d.ts states that it is of type HTMLElement while it should be Element (see the spec).
This is arguable, because there was complainant before saying that it was too cumbersome to always cast the type Element to HTMLElement when in most common cases the actual type is HTMLElement, even though the spec says it should be Element.
For example, the return type of getElementById is defined as Element, however we made it HTMLElement to avoid too much casting. If the type is some other Element, you can just cast it to Element first and then cast it again to the final type. I think in most cases the parentElement is HTMLElement too, therefore it might be better just leave it the way it is.
Reacted by Peter Hultqvist, Orkhan Alikhanov, fregante and Krzysztof Kruk
Reacted by Benjamin Strauß, Tibor Halter, Andreas von Burg, Alex Kulikov, Daniel M., Alexandre A. Bizri, Jay Faulkner, Robbie Speed, Armagan Amcalar, Trotyl Yu and 25 more
What's the status of this issue in 2019? Right now the method is defined
as Document.getElementById(elementId: string): HTMLElement | null which cause an error if the element is SVGSVGElement and the workaround is to cast this element as SVGGraphicsElement | any type. But what is the final conclusion of this discussion? Should the method Document.getElementById(id) return Element or HTMLElement | SVGSVGElement | null? Because imo casting the types isn't anything good, is just a temporary fix.
Reacted by Reinis Ivanovs, Marquizzo, Dominik Paľo, Christopher Dieringer, Tomáš Mládek, Leon Yu and Lauren Yim
While I understand the rationale behind the decision to make the type HTMLElement instead of Element, considering it's plainly against the spec and causing trouble for people working with non-HTML documents, I would urge to reconsider.
Or as a compromise, given the overwhelming majority use-case, I'd be in favor of making it a tsconfig.json option as suggested in #32822, I believe this has potential to satisfy both use cases.
Reacted by Alexey Elizarov, Alexey Lyakhov, Jimmy and Lutymane
@jun-sheaf sent a PR for these changes and I've been reviewing about whether it should make it in for 4.1.
I don't think we should make these changes, because it's going to add break a lot of code in a way that people won't think is to their advantage. TS tries to balance correctness and productivity and I think making getElementById start returning code which needs to be casted to get the same tooling support we have today in the majority of cases (e.g. HTML nodes in a JS context) is going to be a bad call for TypeScript.
The main crux of the PR is changes like these:
- getElementById(elementId: string): HTMLElement | null;+ getElementById<E extends Element = Element>(elementId: string): E | null;
Meaning in the old version to use an SVG/XML element meant doing something like:
Without a cast, which would hit the TypeScript Website's codebase a few times (but I could switch to . textContent in those cases) and you lose the addEventListener/removeEventListener auto-complete map: e.g.
And this means you don't get a typed event anymore. Which I don't think is worth the change to getElementById<E extends Element = Element>(elementId: string): E | null.
Switching it to getElementById<E extends Element = HTMLElement>(elementId: string): E | null on the other hand still allows for setting the return type less drastic ways for the uncommon cases:
const logo2 = getElementById2("my-logo") as SVGPathElement
const logo3 = getElementById2<SVGPathElement>("my-logo")
But doesn't hinder the default JS tooling support.
Hate to interject, as I do agree with your assessment of the trade-offs involved, but I would like to hear your opinion on making it a project-wide setting (#32822) - wouldn't that also alleviate the productivity/JS default issues?
Personally, I'm super hesitant to add more flags and options to TS, there's already 100+ - but I'd let the TS team as a whole make that call
IMO, the strictest/most compliant version can ship as a .d.ts which can modify the DOM types to be stricter globally though:
// Default with lib.dom.d.tsinterfaceDocument{getElementById<EextendsElement=HTMLElement>(elementId: string): E|null}// In something like in @types/strict-dom/index.d.tsinterfaceDocument{getElementById<EextendsElement=Element>(elementId: string): E|null}consta=document.getElementById("e")!a.innerText// bails
Which means this can effectively live in user-land instead of it having to be inside the compiler, having a library means it can support more than just the recommendations here too
Reacted by Holger Jeromin, fregante, __, Tomáš Mládek and Haroen Viaene
Activity
zhengbli commentedon Oct 7, 2015
This is arguable, because there was complainant before saying that it was too cumbersome to always cast the type
ElementtoHTMLElementwhen in most common cases the actual type isHTMLElement, even though the spec says it should beElement.For example, the return type of
getElementByIdis defined asElement, however we made itHTMLElementto avoid too much casting. If the type is some otherElement, you can just cast it toElementfirst and then cast it again to the final type. I think in most cases theparentElementisHTMLElementtoo, therefore it might be better just leave it the way it is.leonyu commentedon Nov 22, 2015
I just encountered this bug. The issue occurred with SVG on the page.
Maybe this can be solved with generics? Though the syntax would be ridiculous. (e.g.
Node<Element<HTMLElement>>>14 remaining items
karolkarolka commentedon Jan 21, 2019
What's the status of this issue in 2019? Right now the method is defined
as
Document.getElementById(elementId: string): HTMLElement | nullwhich cause an error if the element isSVGSVGElementand the workaround is to cast this element asSVGGraphicsElement | anytype. But what is the final conclusion of this discussion? Should the methodDocument.getElementById(id)returnElementorHTMLElement | SVGSVGElement | null? Because imo casting the types isn't anything good, is just a temporary fix.falsandtru commentedon Aug 12, 2019
Also see #32822.
tmladek commentedon Jul 6, 2020
What's the status of this issue in 2020?
While I understand the rationale behind the decision to make the type
HTMLElementinstead ofElement, considering it's plainly against the spec and causing trouble for people working with non-HTML documents, I would urge to reconsider.Or as a compromise, given the overwhelming majority use-case, I'd be in favor of making it a
tsconfig.jsonoption as suggested in #32822, I believe this has potential to satisfy both use cases.RyanCavanaugh commentedon Jul 8, 2020
orta commentedon Sep 10, 2020
@jun-sheaf sent a PR for these changes and I've been reviewing about whether it should make it in for 4.1.
I don't think we should make these changes, because it's going to add break a lot of code in a way that people won't think is to their advantage. TS tries to balance correctness and productivity and I think making
getElementByIdstart returning code which needs to be casted to get the same tooling support we have today in the majority of cases (e.g. HTML nodes in a JS context) is going to be a bad call for TypeScript.The main crux of the PR is changes like these:
Meaning in the old version to use an SVG/XML element meant doing something like:
Which isn't great, and now you can write:
Which is better.
But we lose something in the trade-off, and that is the tooling support for JS (because it always uses the defaults)
With the changes to make it exactly the same as the spec, you can no-longer write code like:
Without a cast, which would hit the TypeScript Website's codebase a few times (but I could switch to
. textContentin those cases) and you lose theaddEventListener/removeEventListenerauto-complete map: e.g.And this means you don't get a typed event anymore. Which I don't think is worth the change to
getElementById<E extends Element = Element>(elementId: string): E | null.Switching it to
getElementById<E extends Element = HTMLElement>(elementId: string): E | nullon the other hand still allows for setting the return type less drastic ways for the uncommon cases:But doesn't hinder the default JS tooling support.
Notes
tmladek commentedon Sep 10, 2020
Hate to interject, as I do agree with your assessment of the trade-offs involved, but I would like to hear your opinion on making it a project-wide setting (#32822) - wouldn't that also alleviate the productivity/JS default issues?
orta commentedon Sep 10, 2020
Personally, I'm super hesitant to add more flags and options to TS, there's already 100+ - but I'd let the TS team as a whole make that call
IMO, the strictest/most compliant version can ship as a .d.ts which can modify the DOM types to be stricter globally though:
Which means this can effectively live in user-land instead of it having to be inside the compiler, having a library means it can support more than just the recommendations here too
Revert "Replaces several DOM methods with weaker typings and closes m…
starball5 commentedon Mar 5, 2023
Related question on Stack Overflow: Why isn't the
styleproperty suggested for the result ofdocument.querySelector()?Merge pull request microsoft#885 from jun-sheaf/master