React defines some (not all) DOM types in a file called global.d.ts
, which is causing problems. There seems to be a conflict when using the EventListener
type (coming from the TypeScript lib dom
) in a React project, because most other types are declared by React.
Is there any way of using the EventListener
type in a React project? I am using next.js, so possibly it is not a good idea to discard the global.d.ts file using exclude
in the tsconfig.json
for SSR to work?
What is expected (pure TS):
https://codesandbox.io/s/nice-tdd-xnkov?file=/src/index.ts
window.onload = () => {
// NO Problem: Listener is correct.
// Explanation:
// EventListener is coming from typescript (lib.dom.d.ts)
// MouseEvent is coming from typescript (lib.dom.d.ts)
const listener: EventListener = (ev: MouseEvent) => {
console.log("Click!");
};
document.body.addEventListener("click", listener);
};
Does not work in React:
https://codesandbox.io/s/react-dom-type-conflict-1y06r?file=/src/App.tsx
useEffect(() => {
// Problem: Listener is seemingly incorrect.
// Explanation:
// EventListener is coming from typescript (lib.dom.d.ts)
// MouseEvent is coming from react (global.d.ts)
const listener: EventListener = (ev: MouseEvent) => {
console.log("Click!");
};
document.body.addEventListener("click", listener);
}, []);
The explanation, why React is declaring these types (from global.d.ts
):
React projects that don't include the DOM library need these interfaces to compile. React Native applications use React, but there is no DOM available. The JavaScript runtime is ES6/ES2015 only. These definitions allow such projects to compile with only
--lib ES6
.Warning: all of these interfaces are empty. If you want type definitions for various properties (such as HTMLInputElement.prototype.value), you need to add
--lib DOM
(via command line or tsconfig.json).
Edit: As @Christoph Bühler pointed out it appears that addEventListener event handler receives a MouseEventInit
instead of MouseEvent
So this works:
const listener: EventListener = (ev: MouseEventInit) => {
console.log("Click!");
const e = ev as MouseEvent;
console.log(e.target);
};
Working CodeSandbox that I forked from yours.