microsoft / microsoft/TypeScript
HTMLElement inherits onerror and addListener("error" definitions that are unique to Window
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
### 🔎 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
```ts
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:
```ts
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()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener), or set an event handler property.
>
> ```js
> addEventListener("error", (event) => { })
>
> onerror = (event) => { }
> ```
>
> #### Event type
> The event object is a [`UIEvent`](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent) instance if it was generated from a user interface element, or an [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/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`](https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event), 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`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) instance if it was generated from a user interface element, or an [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) instance otherwise.
However, the page notes that all of this is unique to `Window`:
> **Note:** For historical reasons, `onerror` on `Window` and [`WorkerGlobalScope`](https://developer.mozilla.org/en-US/docs/Web/API/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`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) object, while the `onerror` handler receives five arguments, matching the [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) object's properties:
> This special behavior only happens for the `onerror` event handler on `window`. The [`Element.onerror`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/error_event) handler still receives a single [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/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.)
Contributor guide
Assessment
This issue has not been assessed yet.