d3 (v4) tree layout and typescript: Property 'x' does not exist on type 'HierarchyNode<IOrgChartNode>'

房东的猫 提交于 2020-01-24 06:26:45

问题


I am trying to use proper ts types while using a d3.hierarchy root with a tree layout, e.g.:

interface MyCustomGraphType {
  id: string;
  children?: MyCustomGraphType[]
}
let treeData: MyCustomGraphType = {/*...*/};
let root = d3.hierarchy(treeData);
let layout = d3.tree().size([500,500])(root);
let nodes = layout.descendants();

// BIND DATA (Node)
let node = this.nodesGroup.selectAll('g.node')
  .data(nodes, d => d.data.person.email); // <--- compile-time error
   // ^^^ Property 'data' does not exist on type '{} | HierarchyNode<MyCustomGraphType>'.

// ... later:
node.enter()
  .append('circle')
  .attr('transform', d => `translate(${d.x}, ${d.y})`); // <--- compile-time error
   // ^^^ Property 'y' does not exist on type '{} | HierarchyNode<MyCustomGraphType>'.

Clearly the first error is because for whatever reason the union type '{} | HierarchyNode<MyCustomGraphType>' is inferred in the key function. The second error is due to the fact that d3.tree adds properties that were previously not defined there.

What's a clean way to approach this while keeping type-safety?

Thanks!

P.S. I am using d3 version 4


回答1:


There are a few things going on here, which should be readily resolvable:

(1) To clarify, I assume that your actual data structure is something more like this:

interface MyCustomGraphType {
  id: string;
  person: {
    email: string;
    /*Other Properties*/
  };
  children?: MyCustomGraphType[];
}

This would explain your accessing the person.email proprty of a node in the selection.data(...) key function.

(2) The D3 definitions make extensive use of generic type parameters. In some cases type inference will serve them up readily. In others, they cannot be readily inferred.

  • Use d3.tree<MyCustomGraphType>().size([500,500])(root); This will return a tree layout root point of type HierarchyPointNode<MyCustomGraphType>. By implication nodes will now be an HierarchyPointNode<MyCustomGraphType>[] array.
  • select, selectAll, append and data from the d3-selection module have extensive JSDoc comments regarding the various overloaded signatures' generics. They should be available as mouseover hints or similar in the code editor (e.g. VS Code).

(3) The reason why the key accessor in the data method call errors out, is as follows: The key accessor is used to match old and new data entries. The old data type is based on the preceding selectAll(...) statement. Given that the generic types of the selected elements and their "old" data type cannot be inferred from a string-based selector, they must be set explicitly. Otherwise, the "old" data type defaults to {}. That is why you see the union data type {} | HierarchyPointNode<MyCustomGraphType>. Care must be taken that the "old" data type of the selected elements is in synch between the actual selected elements and the key accessor. The key function should have a way to handle edge cases, if needed.

(4) As for the missing properties x or y, I do not seem to able to replicate this issue. For me they are present, as the data type of d in

attr('transform', d => `translate(${d.x}, ${d.y})`)

is correctly inferred as HierarchyPointNode<MyCustomGraphType>.

Hopefully this explains.



来源:https://stackoverflow.com/questions/45356346/d3-v4-tree-layout-and-typescript-property-x-does-not-exist-on-type-hierarc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!