d3(v4)树的布局和打字稿:属性&#39; x&#39;在类型&#39; HierarchyNode <iorgchartnode>&#39;上不存在

时间:2017-07-27 16:30:59

标签: typescript d3.js

我正在尝试使用具有树状布局的d3.hierarchy根时使用正确的ts类型,例如:

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>'.

显然,第一个错误是因为无论出于何种原因,在'{} | HierarchyNode<MyCustomGraphType>'函数中推断出了联合类型key。第二个错误是由于d3.tree添加了以前未在那里定义的属性。

在保持类型安全的同时,采用干净的方法是什么?

谢谢!

P.S。我正在使用d3版本4

1 个答案:

答案 0 :(得分:3)

这里有一些事情,应该很容易解决:

(1)为了澄清,我假设您的实际数据结构更像是这样:

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

这可以解释您访问person.email键功能中节点的selection.data(...)属性。

(2)D3定义广泛使用泛型类型参数。在某些情况下,类型推断可以很容易地为它们服务。在其他情况下,不能轻易推断出它们。

  • 使用d3.tree<MyCustomGraphType>().size([500,500])(root);这将返回HierarchyPointNode<MyCustomGraphType>类型的树布局根点。暗示nodes现在将成为HierarchyPointNode<MyCustomGraphType>[]数组。
  • 来自 d3-selection 模块的
  • selectselectAllappenddata对各种重载签名的泛型有广泛的JSDoc评论。它们应该在代码编辑器中以鼠标悬停提示或类似方式提供(例如VS代码)。

(3)data方法中的密钥访问者调用错误的原因如下:密钥访问者用于匹配 new 数据条目。旧数据类型基于前面的selectAll(...)语句。鉴于无法从基于字符串的选择器推断所选元素的泛型类型及其“旧”数据类型,因此必须明确设置它们。否则,“旧”数据类型默认为{}。这就是你看到联合数据类型{} | HierarchyPointNode<MyCustomGraphType>的原因。必须注意所选元素的“旧”数据类型在实际所选元素和密钥访问者之间是同步的。如果需要,关键功能应该有办法处理边缘情况。

(4)对于缺失的属性xy,我似乎无法复制此问题。对我来说,它们存在,作为<{p>中的d的数据类型

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

被正确推断为HierarchyPointNode<MyCustomGraphType>

希望这可以解释。