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

How to narrow type of querySelectorAll results? #141

Closed
vwkd opened this issue Aug 25, 2023 · 5 comments
Closed

How to narrow type of querySelectorAll results? #141

vwkd opened this issue Aug 25, 2023 · 5 comments

Comments

@vwkd
Copy link

vwkd commented Aug 25, 2023

I'm getting type errors when iterating over a node list of elements.

import { DOMParser } from "deno_dom";

const doc = new DOMParser().parseFromString(html, "text/html")!;

const anchors = doc.querySelectorAll("a");

for (const anchor of anchors) {
  const href = anchor.getAttribute("href");
  // Property 'getAttribute' does not exist on type 'Node'.
}

How can I narrow the types to an (anchor) element type?

The signature querySelectorAll(selectors: string): NodeList suggest NodeList is missing a generic type such that we can supply an element type to narrow it down.

Interestingly, the signature querySelector(selectors: string): Element | null always returns an element instead of a node. Does querySelector never return a non-element node? If so, then why can querySelectorAll?

@b-fuze
Copy link
Owner

b-fuze commented Aug 25, 2023

You want to add a type assertion for Element:

import { DOMParser, Element } from "deno_dom";

// ...

for (const anchor of anchors) {
  const href = (anchor as Element).getAttribute("href");
}

@vwkd
Copy link
Author

vwkd commented Aug 25, 2023

That's what I'm currently doing but it's feels not ideal. For example, if used multiple times it requires assertions at each place, or a dummy reassignment.

Would it be possible to make NodeList generic, such that one can supply NodeList<Element> and querySelectorAll<Element>("a")?

@b-fuze
Copy link
Owner

b-fuze commented Aug 25, 2023

Yeah, that's basically #4. When I get some time I'll make it happen. After I do that I'll have to make the different HTML element classes as well

@jakubdonovan
Copy link

Yeah, that's basically #4. When I get some time I'll make it happen. After I do that I'll have to make the different HTML element classes as well

I'm a little confused. How do I narrow down the HTMLElement type to HTMLImageElement?
While working with jsdom, I would do this to access the src attribute:

const images = [
    ...new Set(
      [...owlDemoEl.querySelectorAll<HTMLImageElement>("img")].map((img) => img.src),
    ),
  ];

But while using deno-dom, the same code would give me an error saying that src does not exist because img is typed as HTMLElement. Of course, I could do it like so, but it's not as clean in my opinion.

const images = [
   ...new Set(
     [...owlDemoEl.querySelectorAll("img")].map((img) =>
       img.getAttribute("src")
     ),
   ),
 ];

What did I miss?

@vwkd
Copy link
Author

vwkd commented Oct 15, 2024

This issue should have been closed with #162 and #175.

@jakubdonovan Specific element types and APIs like img.src are a slightly different issue and AFAIK not supported yet. See #72.

@vwkd vwkd closed this as completed Oct 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants