Reputation: 4527
I have a group of widgets developed with d3 (version 5) and now I have to migrate them to version 7. In the migration guide https://observablehq.com/@d3/d3v6-migration-guide I've learned the new syntax for events:
// before
element.on('click', (d, i, e) => ...
// now
element.on('click', (event, d) => ...
Once I switched to the new syntax the program started running again. Yay!
The issue now is that I use typescript in this project! And Though I have installed the latest @types/...
"dependencies": {
"d3": "^7.1.1",
...
"devDependencies": {
"@types/d3": "^7.1.0",
...
...I keep having trouble with type definitions and Intellisense when it comes to events.
// 1. before (Worked fine)
element.on('click', (d: MyData, i: number, e: whatever[]) => ...
// 2. introducing types == Error back! ❌
element.on('click', (event: PointerEvent, d: MyData) => ...
// 3. then, my (ugly) workaround:
element.on('click', (event: any , d: any) => ...
What's funny is that though I have @types/d3 v7.0.1 installed, the Typings system looks like it still holds reference to the old v5 format. Somehow Intellisense still thinks my first param is data and the second is a numeric index:
...But in real life what I get is { event: PointerEvent, d: MyData }, as shown in the picture below.
So, in a nutshell, feels like there's a problem with D3's types declaration as Intellisense thinks the Event's still under the v5 format while in real life it's not.
Do anyone know how to fix this typing thing? It's really annoying having to assign "any" to the whole thing inside my events.
Upvotes: 8
Views: 1969
Reputation: 124
I solved this by adding a utility type of D3Event
to my codebase that accepts 2 type args:
export type D3Event<T extends Event, E extends Element> = T & { currentTarget: E }
Then I can use it like this:
selection.on('mouseover', (event: D3Event<MouseEvent, SVGGElement>, d: SomeType) => { ... }
It's a little more verbose but it's much stricter than any
Upvotes: 3
Reputation: 21578
As you are well aware, it is usually best practice to avoid any
like the Plague, which is the reason why you are trying to narrow it down to a particular type! In case of the event listener's type definition you are out of luck, though. Looking at the the .on
method's definition you will notice that the event
parameter is indeed typed as any
allowing for the most generic event handling:
on(typenames: string, listener: (this: GElement, event: any, d: Datum) => void, options?: any): this;
For that reason, your second approach is going to fail leaving you with the third approach as the correct solution.
Upvotes: 4