Angular 如何在d3中使用SimulationLinkDatum和SimulationNodeDatum

Angular 如何在d3中使用SimulationLinkDatum和SimulationNodeDatum,angular,typescript,d3.js,Angular,Typescript,D3.js,我在使用SimulationLinkDatum类型时遇到问题。我创建了两个类Node和Link,它们实现了SimulationNodeDatum和SimulationLinkDatum。当我尝试使用SimulationLinkDatum类型脚本时,d.source.x、d.target.x等类型脚本说“属性“x”在类型“string | number | Node”上不存在。” 我理解SimulationLinkDatum接受源节点和目标节点属性的number | string |,如果使用nu

我在使用SimulationLinkDatum类型时遇到问题。我创建了两个类Node和Link,它们实现了SimulationNodeDatum和SimulationLinkDatum。当我尝试使用SimulationLinkDatum类型脚本时,d.source.x、d.target.x等类型脚本说“属性“x”在类型“string | number | Node”上不存在。

我理解SimulationLinkDatum接受源节点和目标节点属性的
number | string |
,如果使用number或string,它将变异为SimulationNodeDatum。这只是我们必须接受的东西,还是有更好的方法使用这些接口

谢谢

class D3Component {
    private createPathString(d: SimulationLinkDatum<Node>) {
        return 'M' + d.source.x + ',' + d.source.y + 'L' + d.target.x + ',' + d.target.y;
    }
}
class Node implements SimulationNodeDatum {
    public x: number;
    public y: number;
    constructor (public id: number) {}
}

class Link implements SimulationLinkDatum<Node> {
    constructor (public source: Node, public target: Node)  {}
}
D3类组件{
私有createPathString(d:SimulationLinkDatum){
返回'M'+d.source.x+'、'd.source.y+'L'+d.target.x+'、'+d.target.y;
}
}
类节点实现SimulationNodeDataum{
公共x:数字;
公众y:数字;
构造函数(公共id:number){}
}
类Link实现SimulationLinkDatum{
构造函数(公共源:节点,公共目标:节点){}
}

正如您正确指出的那样,d3 force的TypeScript定义反映了实际JS实现中固有的改变节点和链接数据结构的方法

具体而言,对于
SimulationLinkDatum
接口,建议的做法是使用自定义类型的防护装置,例如:

function isNodeObject<T>(node: number | string| T): node is T {
    return typeof node !== 'number' && typeof node !== 'string';
}
函数是nodeObject(节点:number | string | T):节点是T{
返回节点的类型!='number'&&typeof节点!='string';
}
然后,可以像往常一样使用TypeScript的类型缩小功能,例如,在上述情况下:

private createPathString(d: SimulationLinkDatum<Node>) {
  if (isNodeObject(d.source) && isNodeObject(d.target)) {
    return 'M' + d.source.x + ',' + d.source.y + 'L' + d.target.x + ',' + d.target.y;
  } else {
    return '';
  }
}
private createPathString(d:SimulationLinkDatum){
if(isNodeObject(d.source)和&isNodeObject(d.target)){
返回'M'+d.source.x+'、'd.source.y+'L'+d.target.x+'、'+d.target.y;
}否则{
返回“”;
}
}
虽然这是最可重用的方法,但在某些情况下,以下两种方法可能更适合:

(1) 如果已知给定的代码段将仅在已初始化的链接上调用,则可以简单地强制转换
(d.source).x
。对强制转换节点对象使用局部变量可以提高下游可读性

(2) 在
if
-子句中直接使用类型缩小,而不创建可重用的自定义类型保护

鉴于当前定义接口的方式,这些是访问变异属性中对象的关键方法