b-fuze / deno-dom

Browser DOM & HTML parser in Deno
https://jsr.io/@b-fuze/deno-dom
MIT License
412 stars 48 forks source link

How to narrow type of `querySelectorAll` results? #141

Open vwkd opened 1 year ago

vwkd commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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