tezvyn:

Typing NodeList vs. HTMLCollection in TypeScript

AI-drafted, machine-checkedSource: developer.mozilla.orgintermediate
Typing NodeList vs. HTMLCollection in TypeScript

NodeList can contain any node (elements, text, comments), while HTMLCollection only holds elements. TypeScript forces you to handle this. Use querySelectorAll for a NodeList, or getElementsByTagName for an HTMLCollection.

WHY IT EXISTS The DOM API has different methods for selecting groups of nodes. Some methods return collections that can include anything (elements, text, comments), while others are guaranteed to return only elements. TypeScript's type system makes this distinction explicit to prevent runtime errors before your code ever runs.

THE MENTAL MODEL Think of a NodeList as a mixed bag of DOM nodes and an HTMLCollection as a curated box of just HTML elements. NodeList is more general, typically returned by querySelectorAll. HTMLCollection is more specific, returned by methods like getElementsByTagName or the .children property. TypeScript forces you to acknowledge what's in the bag before you try to use it.

HOW IT WORKS In TypeScript, querySelectorAll returns a NodeList. If you iterate over it, each item is typed as Node. The Node type is generic; it doesn't have properties like .id or .style. To access those, you must first check if the node is an Element using a type guard like if (node instanceof Element). In contrast, getElementsByTagName returns an HTMLCollection, which is generically typed as HTMLCollection<Element>. Its items are already known to be Elements, so you can access element properties directly without a check.

WHEN TO USE IT Use NodeList (from querySelectorAll) when you need the power of complex CSS selectors to grab a static, unchanging list of nodes. Use HTMLCollection (from getElementsByTagName or .children) when you need a "live" collection that automatically updates as the DOM changes, and you only care about element nodes.

WHEN NOT TO USE IT Don't assume a NodeList contains only elements. The source MDN example shows node.childNodes returning a NodeList with an HTMLParagraphElement, a Text node, and an HTMLSpanElement. Trying to set .style on the text node would fail at runtime. Also, be aware that HTMLCollection is live, which can cause unexpected behavior or infinite loops if you modify the collection while iterating over it.

ONE CANONICAL EXAMPLE When using querySelectorAll, you get a NodeList. To access element properties, you need a type guard. For example: const nodes = document.querySelectorAll('.item'); nodes.forEach(node => { if (node instanceof HTMLElement) { node.style.color = 'red'; } });. Without the if check, TypeScript would throw an error because a generic Node has no .style property. In contrast, getElementsByTagName('div') returns an HTMLCollection. Its items are already typed as Element, so you can iterate and access .style directly, for instance, inside a standard for loop.

Read the original → developer.mozilla.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.