javascripttypescriptvisual-studio-codeaddeventlistener

Why does addEventListener() only get suggestions for the fullscreenchange and fullscreenerror events on an element from document.querySelector?


What I want (an example of all the events suggested for addEventListener on the document object):
1. It is what i want

What I have (events suggested for addEventListner on the object returned from my document.querySelector query (only fullscreenchange and fullscreenerror)):
2. there is no suggestion at this

I want suggestions as shown in the first image.

Here's a transcription of the above images so you can try for yourself:

const titleElement = document.querySelector("#title");

document.addEventListener("", (ev) => {});
// ^lots of suggested event names

titleElement.addEventListener("", (ev) => {});
// ^only the `fullscreenchange` and `fullscreenerror` events are suggested

Solution

  • This is due to typing. document.querySelector is only guaranteed to return an element of type Element, although, of course, it can return an object of a subtype of Element. But for the type definitions in lib.dom.ts, Element is only defined to have those two events (fullscreenchange and fullscreenerror) on them- probably because those are the only two events that are valid for all possible Element subtypes.

    To solve your problem, you can pass the type you expect as a generic argument to the querySelector call, like this:

    document.querySelector<HTMLHeadingElement>("#title")
    

    which will type the returned object as HTMLHeadingElement | null.

    Alternatively, you can add a type assertion to tell the TypeScript compiler or VS Code the exact type you expect that queried element to be.

    In TypeScript, you can do a type assertion with the as keyword like this (you need to add | null yourself if you want it):

    const titleElement = document.querySelector("#title") as HTMLHeadingElement;
    // or whatever HTML type your `#title`-IDed element is.
    

    In JavaScript, you can use JSDoc comments to make type hints that VS Code and other tools will recognize:

    /** @type {HTMLHeadingElement} */
    const titleElement = document.querySelector("#title");
    

    Or, you can wrap your usage of the object returned from the query with a type check:

    const titleElement = document.querySelector("#title");
    if (titleElement instanceof HTMLHeadingElement) {
      titleElement.addEventListever("click", (ev) => {
        console.log("hello world!");
      });
    }
    

    The TypeScript language server that powers IntelliSense in VS Code will know that inside that if-block, the type of titleElement must be at least HTMLHeadingElement (or whatever type you specify in the instanceof check) because of the instanceof check. You can read more about the instanceof operator on MDN.

    To get a list of all existing HTML elements, one place to look is MDN's HTML Element Reference page, or you can just type HTML in your file in VS Code and trigger autocomplete suggestions.