Description
TypeScript Version: 2.7.0-dev.201xxxxx
Code
npm install typescript jsdom @types/jsdom
// example.ts
import { JSDOM } from 'jsdom';
let dom = new JSDOM(`
<!DOCTYPE html>
<html>
<head>
<title>Test DOM</title>
</head>
<body>
<input type="button" id="button" />
</body>
</html>
`);
let window = dom.window;
let elem = window.document.getElementById('button');
elem.onclick = (ev: MouseEvent) => {
console.log(`Button clicked, typeArg: ${ev.type}`);
}
let event: MouseEvent = new window.MouseEvent('someTypeArg');
elem.onclick(event);
Expected behavior:
TypeScript compiles, running node example.js
outputs the following to console, then exits:
Button clicked, typeArg: someTypeArg
Actual behavior:
TypeScript fails to compile with the following error:
example.ts(19,36): error TS2339: Property 'MouseEvent' does not exist on type DOMWindow
@types/jsdom defines the DOMWindow
interface as:
export interface DOMWindow extends Window { eval(script: string): void; }
The Window
interface it extends is the one defined by TypeScript. That interface is missing definitions for the Event types, although these Event types are declared outside the Window
interface. In web browsers, the Event types exist both globally and on the window
object. TypeScript currently handles the former but not the latter.
jsdom does in fact implement the Event types on the dom.window
object. You can modify the code above to compile and behave as expected by extending the DOMWindow
interface, adding the MouseEvent
type to it, and casting the dom.window
object to this newly defined interface:
import { JSDOM, DOMWindow } from 'jsdom';
interface WindowWithMouseEvent extends DOMWindow {
MouseEvent: {
prototype: MouseEvent;
new(typeArg: string, eventInitDict?: MouseEventInit): MouseEvent;
}
}
let dom = new JSDOM(`
<!DOCTYPE html>
<html>
<head>
<title>Test DOM</title>
</head>
<body>
<input type="button" id="button" />
</body>
</html>
`);
let window = dom.window as WindowWithMouseEvent;
let elem = window.document.getElementById('button');
elem.onclick = (ev: MouseEvent) => {
console.log(`Button clicked, typeArg: ${ev.type}`);
}
let event: MouseEvent = new window.MouseEvent('someTypeArg');
elem.onclick(event);
I've spoken to the maintainer of @types/jsdom (see this issue) and they suggested raising an issue with your team instead. I agree, seeing as Event types exist on the window
object in web browsers.