Tengo un problema al utilizar SimulationLinkDatum Type. Hice dos clases Node y Link que implementan SimulationNodeDatum y SimulationLinkDatum. Cuando voy a probar y usar SimulationLinkDatum mecanografiado dice que d.source.x, d.targe.x, etc. mecanografiado dice que " La propiedad 'x' no existe en el tipo 'cadena | número | Nodo'".
Entiendo que SimulationLinkDatum acepta number | string | <T> para las propiedades del nodo de origen y de destino y que, si usa un número o una cadena, se transformará en un SimulationNodeDatum. ¿Es esto algo con lo que tenemos que vivir o hay una mejor manera de usar estas interfaces?
Gracias
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) {} }Como señala correctamente, las definiciones de TypeScript para d3-force reflejan el enfoque para mutar las estructuras de datos de enlace y nodo inherentes a la implementación real de JS.
Específicamente, para la interfaz SimulationLinkDatum<NodeDatum extends SimulationNodeDatum> , la práctica sugerida es usar un tipo de protección personalizado, por ejemplo:
function isNodeObject<T>(node: number | string| T): node is T { return typeof node !== 'number' && typeof node !== 'string'; }Luego, el tipo de estrechamiento de TypeScript se puede usar como de costumbre, por ejemplo, en su caso anterior:
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 ''; } }Si bien este es el enfoque más reutilizable, las siguientes dos alternativas pueden ser más adecuadas en algunas situaciones:
(1) Si se sabe que un segmento de código dado solo se invocará en enlaces que ya se han inicializado, entonces uno puede simplemente lanzar (<SimNode>d.source).x . El uso de variables locales para los objetos del nodo de conversión puede mejorar la legibilidad en sentido descendente.
(2) Utilice el tipo de estrechamiento directamente en una cláusula if sin crear una protección de tipo personalizada reutilizable.
Dada la forma en que las interfaces están definidas actualmente, estas son las formas clave de acceder a los objetos en las propiedades mutadas.