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