Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should the $ function return HtmlElement? #5074

Closed
yebrahim opened this issue Jan 30, 2018 · 16 comments
Closed

Should the $ function return HtmlElement? #5074

yebrahim opened this issue Jan 30, 2018 · 16 comments

Comments

@yebrahim
Copy link

yebrahim commented Jan 30, 2018

Now it's typed to return a Polymer.Element, which almost always is not going to be the case. Why doesn't it just return an HTMLElement and let the user cast it if needed?

$: {[key: string]: Element};

@TimvdLippe
Copy link
Contributor

TimvdLippe commented Jan 30, 2018 via email

@kevinpschaaf
Copy link
Member

As @TimvdLippe said, the intention is that the type is window.Element (since an id-mapped element could be a HTMLElement or SVGElement), and not Polymer.Element.

In the current 3.0-preview, modulizer converts the global Polymer.Element to Element as in (import Element from 'polymer-element.js'), however we intend to soon change modulizer to rename Polymer.Element to something other than Element to avoid confusion and actual scope-shadowing errors like this. We just need to decide on a better name.

aomarks added a commit that referenced this issue Feb 1, 2018
Polymer defines its own `Element` class, shadowing the standard global
`Element` class. This means that references to `Element` within the
`Polymer` namespace inadvertently reference `Polymer.Element`. Here we
define an alias of the global `Element`, so that we can reference it
from declarations within the `Polymer` namespace.

See microsoft/TypeScript#983 for general
discussion of this shadowing problem in TypeScript.

Fixes #5074
aomarks added a commit that referenced this issue Feb 1, 2018
Polymer defines its own `Element` class, shadowing the standard global
`Element` class. This means that references to `Element` within the
`Polymer` namespace inadvertently reference `Polymer.Element`. Here we
define an alias of the global `Element`, so that we can reference it
from declarations within the `Polymer` namespace.

See microsoft/TypeScript#983 for general
discussion of this shadowing problem in TypeScript.

Fixes #5074
@aomarks
Copy link
Member

aomarks commented Feb 1, 2018

Just sent #5084 that should fix this issue for 2.x by defining a global _Element alias and updating all the references (the generator lets us do renames through the config file).

@yebrahim
Copy link
Author

yebrahim commented Feb 1, 2018

Thanks for the quick turnaround.

aomarks added a commit that referenced this issue Feb 1, 2018
Polymer defines its own `Element` class, shadowing the standard global
`Element` class. This means that references to `Element` within the
`Polymer` namespace inadvertently reference `Polymer.Element`. Here we
define an alias of the global `Element`, so that we can reference it
from declarations within the `Polymer` namespace.

See microsoft/TypeScript#983 for general
discussion of this shadowing problem in TypeScript.

Fixes #5074
@floribon
Copy link
Contributor

floribon commented Feb 3, 2018

I just updated to Polymer 2.5 and this seems to create an issue with the TypeScript compiler as the global "Element" type is different from "HTMLElement" that was what I was getting from the $ function.

crop

@dfreedm
Copy link
Member

dfreedm commented Feb 3, 2018

HTMLElement is a subclass of Element in the browser, so this may actually be correct. Ping @aomarks

@floribon
Copy link
Contributor

floribon commented Feb 3, 2018

It is, but previously we were getting this subclass HTMLElement so if it is the expected behavior that is a breaking change which should be stated in the release note. Current TS workaround is

const htmlElem = this.$.myId as HTMLElement;

@dfreedm
Copy link
Member

dfreedm commented Feb 3, 2018

Whoops, looks like the accidental shadowing of Element in typescript with Polymer.Element that was fixed in 2.5.0 was hiding the fact that this.$ has an incorrect typing. It should be a map of string to HTMLElement.
I'll file a bug.

@dfreedm
Copy link
Member

dfreedm commented Feb 3, 2018

Edit: HA, actually _this_ issue is exactly what you're hitting.

@yebrahim
Copy link
Author

yebrahim commented Feb 3, 2018

Yup. Any ideas when this will be out though? Or which version it's targeting?

@dfreedm
Copy link
Member

dfreedm commented Feb 3, 2018

@floribon Ok, after talking with the team, what you're seeing is working as intended.

Previously, the typing for Element would have actually been Polymer.Element which is a subclass of HTMLElement, and why your typing worked as written.

However, this was incorrect as you could have written code that expected all elements from this.$ to be instances of Polymer.Element, which could result in runtime errors, such as
let el = this.$.actuallyADiv.polymerSpecificAPI(), or if the element in this.$ was actually an SVGElement as @kevinpschaaf said here.

That said, I think we could be open to a new API to make Typescript integration a bit easier, such as the magic tagname typing that Element.prototype.querySelector('div') -> HTMLDivElement can provide.

@floribon
Copy link
Contributor

floribon commented Feb 3, 2018

@azakus thanks and sorry I missed the comment about the potential SVG match, it makes total sense. It may still be considered a potential breaking change or at least "meaningful change" even if it's a bug fix though.

@TimvdLippe
Copy link
Contributor

I have opened a PR Polymer/gen-typescript-declarations#100 to generate these types automatically

@yebrahim
Copy link
Author

yebrahim commented Apr 3, 2018

I still think the returned type should be HTMLElement and not Element. Why make the assumption that the user will use this mostly for Polymer elements? I use this a lot to perform general DOM manipulations on child elements, and even if these elements are Polymer elements, I'll either need to reference their HTMLElement properties, or their own definitions, such as PaperInput for example. Both of these scenarios now require casting.

Let me know if you think this isn't the more common way of using the API, or if it's not what the API was meant for.

@TimvdLippe
Copy link
Contributor

@yebrahim Note that with Element we mean https://developer.mozilla.org/en-US/docs/Web/API/Element, not Polymer.Element. E.g. HTMLElement is a subclass of Element and the list CAN therefore contain both HTMLElement and Polymer.Element as well as other classes such as https://developer.mozilla.org/en-US/docs/Web/API/SVGElement

@yebrahim
Copy link
Author

yebrahim commented Apr 3, 2018

Ah, that makes sense, my bad I didn't spot the difference. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants