Skip to content

HTMLElement inherits onerror and addListener("error" definitions that are unique to Window #62075

@krryan

Description

@krryan

🔎 Search Terms

onerror GlobalEventHandlers

🕗 Version & Regression Information

As far as I can tell, this has always been wrong. There are a number of issues (and merged fixes) around onerror and/or addEventListener("error", but all of them have concerned themselves with getting the definition correct for Window.

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/CYUwxgNghgTiAEYD2A7AzgF3gCwwWwgFEIQ8QUMAueACQBUBZAGWNPIwG4AoL3A1shQB0qEDBhIYACikgAbu2qEFFAJTwAvAD54AbwC+qjvAD0J+GmxIArhGDwUSLGIkwuQA

💻 Code

declare const htmlElement: HTMLElement;

htmlElement.onerror((event: Event) => {}); // should not error

🙁 Actual behavior

The type definitions in lib.dom.d.ts for addEventListener("error" and onerror used by HTMLElement match the spec for Window, which has unique handling of these events for historical reasons.

🙂 Expected behavior

The type definitions in lib.dom.d.ts for addEventListener("error" and onerror event handling on HTMLElement would match the spec for HTMLElement.

Additional information about the issue

In lib.dom.d.ts, we have GlobalEventHandlersEventMap, which is used to define addEventListener, and GlobalEventHandlers, used to define the various on${string} event handler properties. As the name suggests, these are meant to handle “global” events, and Document, Window, HTMLElement, SVGElement, and MathMLElement all inherit these.

Unfortunately, the definitions here for addEventListener("error" and onerror are used uniquely by Window. None of the other types inheriting these definitions are correct for error events.

These are the definitions:

interface GlobalEventHandlersEventMap {
    // …
    "error": ErrorEvent;
    // …
}

interface GlobalEventHandlers {
    // …
    /**
     * Fires when an error occurs during object loading.
     * @param ev The event.
     *
     * [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement/error_event)
     */
    onerror: OnErrorEventHandler;
    // …
}

// …

type OnErrorEventHandler = OnErrorEventHandlerNonNull | null;

// …

interface OnErrorEventHandlerNonNull {
    (event: Event | string, source?: string, lineno?: number, colno?: number, error?: Error): any;
}

Note that MDN link for onerror that specifically directs to HTMLElement/error_event: that page says,

Syntax

Use the event name in methods like addEventListener(), or set an event handler property.

addEventListener("error", (event) => { })

onerror = (event) => { }

Event type

The event object is a UIEvent instance if it was generated from a user interface element, or an Event instance otherwise.

Just a single argument that is either Event or UIEvent. Both the five-argument onerror definition and the single ErrorEvent argument "error" definition are wrong for HTMLElement.

Instead, those definitions are from Window, and are defined correctly for Window, including the discrepancy in the arguments between addEventListener and onerror. Well, the GlobalEventHandlersEventMap definition is possibly less than precise:

The event object is a ErrorEvent instance if it was generated from a user interface element, or an Event instance otherwise.

However, the page notes that all of this is unique to Window:

Note: For historical reasons, onerror on Window and WorkerGlobalScope objects is the only event handler property that receives more than one argument.

The event handler's signature is asymmetric between addEventListener() and onerror. The event handler passed to Window.addEventListener() receives a single ErrorEvent object, while the onerror handler receives five arguments, matching the ErrorEvent object's properties:

This special behavior only happens for the onerror event handler on window. The Element.onerror handler still receives a single ErrorEvent object.

(Side note: the “Element.onerror” link in that last quote actually goes to HTMLElement, and according to that page, it’s a UIEvent or Event, not an ErrorEvent, so MDN has some issues here, too.)

Thus, these definitions should only be applied to Window in lib.dom.d.ts, and onerror/addEventListener("error" for HTMLElement, SVGElement, and MathMLElement should be defined differently. (I can’t actually find definitions of onerror for MathMLElement on MDN, nor for Document which I also see using GlobalEventHandlers in lib.dom.d.ts, but I haven’t dug into those cases much.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions