D3.js and TypeScript compilation error

I am working on Force Dragging I example and was able to get this to work with simple JavaScript. However, when trying to use TypeScript, I have a compilation error.

Problem code (with parts removed):

import * as d3 from "d3";

interface INode {
    id: string;
    group: number;
}

interface ILink {
    source: string;
    target: string;
    value: number;
}

interface IGraph {
    nodes: INode[];
    links: ILink[];
}

var svg = d3.select("svg");

d3.json("data/miserables.json", function (error, graph: IGraph) {

    var node = svg.append("g")
        .selectAll("circle")
        .data(graph.nodes) // Commenting this out, error goes away
        .enter().append("circle")
        .call(d3.drag() // Error here
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended));
});

      

The line .call(d3.drag()

results in the following tsc error:

App.tsx (31,15): error TS2345: argument of type DragBehavior is not assigned to parameter of type '(choice: Select, ... args: any []) => void'. The "selection" and "selection" parameter types are not compatible. The Select type cannot be assigned to the Select type. The "BaseType" type is not assigned to the "Element" type. The type "null" is not assigned to the type "Element".

Similar to d3 v4 drag and drop with TypeScript , there is no error if I change the code to re-select the circles:

var nodes =
  svg.append("g")
  .selectAll("circle")
  .data(graph.nodes)
  .enter().append("circle");

var circle = svg.selectAll("circle");
circle.call(d3.drag()
  .on("start", dragstarted)
  .on("drag", dragged)
  .on("end", dragended));

      

However, when you are not using types, this is unnecessary.

I'm trying to figure out how to work with TypeScript here in order to define variables with appropriate types or whatever is needed to compile it.

+3


source to share


1 answer


Small preamble:

TypeScript definitions for D3 modules make extensive use of generics in interfaces and methods, most importantly, generics are used to control the type of D3 element (s) as well as the type of data that is associated with those elements.

At the heart of your problem:

(1) When you create your drag and drop behavior, make sure the generics match the element type and associated data type corresponding to the element you want to drag. In the above case, this should meand3.drag<SVGCircleElement, INode>()

(2) Make sure your drag and drop event handlers ( dragstarted

, dragged

and dragended

have the appropriate call signature, for example function dragged(this: SVGCircleElement, d: INode) {...}

(you will need to specify the this

-context type if you intend to access it in the callback.)



(3) Make sure the drag type you selected is of the appropriate type. The interface Selection

has four generators, of which the first two again correspond to the type of the selected element and the type of its anchored binding. Selection

methods, such as select

, selectAll

, data

and append

, are generic, the relevant "things" that may affect them. In case, the data

total value can be determined by TS based on the data that is sent to the call. For the other methods mentioned, you may need to explicitly specify what exactly you select or add. For the above, you might consider:

//...
.data<INode>(graph.nodes) // Commenting this out, error goes away
.enter()
.append<SVGCircleElement>("circle")
//...

      

The above changes should ensure that your choices and drag and drop behavior are aligned in a safe manner. For more information, you can refer to the comments in the definitions:

DragBehavior definition or related definition tests here . Definition of choice . Since all of these TS definitions have extensive JSDoc comments, a good IDE will display hints / peeps to let you see them as you write. Pay attention to some of the comments related to generics. Hope this helps.

+5


source







All Articles