Search code examples
typescriptqueryselector

Using querySelector in Typescript: why does it accept HTMLElement return type?


querySelector can return any subtype of Element. On a webpage this would almost certainly be either HTMLElement or SVGElement. The two are not compatible, and yet TypeScript seems happy for me to assign the result of querySelector to an HTMLElement type and access properties specific to HTMLElement. Why doesn't it throw an error?

Here's an example

// why no error on assuming it's going to be HTMLELement
// and not SVGELement or some other Element?
const foo: HTMLElement | null = document.querySelector("*");

if (foo !== null) {
    console.log(foo.hidden);
}

This compiles fine, however foo can actually be an SVGElement.

If I manually set foo's type to be SVGElement then typescript will rightfully complain about accessing the hidden property.

Why doesn't TypeScript catch the mistaken assumption that the return of querySelector is necessarily an HTMLElement?


Solution

  • The signature for the method is

    querySelector<E extends Element = Element>(selectors: string): E | null;
    

    By defining the returned type as HTMLElement (see Type Inference), you've provided the E generic type. Your code is the equivalent of

    const foo = document.querySelector<HTMLElement>('*'); // HTMLElement | null
    

    The only restriction is that E must extend Element.