vasturiano / 3d-force-graph

3D force-directed graph component using ThreeJS/WebGL
https://vasturiano.github.io/3d-force-graph/example/large-graph/
MIT License
4.8k stars 831 forks source link

Question: What is the right syntax for nodeColor(colorAccessor) in TypeScript #311

Open lancegliser opened 4 years ago

lancegliser commented 4 years ago

I just can't seem to get the syntax to correctly the declare the return node type. In types file, it shows:

nodeColor(colorAccessor: NodeAccessor<string>): ChainableInstance;

Which leads to:

type Accessor<In, Out> = Out | string | ((obj: In) => Out);
type NodeAccessor<T> = Accessor<NodeObject, T>;

I'm trying to achieve proper return types from functionality like this:

  const getNodeColor = (item: IFormattedNode): string => {
    if (item.isInError) {
      return errorColor;
    }
    return mutedColor;
  };

  const graph: any = ForceGraph3D()
    .linkWidth(1)
    .nodeColor(getNodeColor);

The actual typescript error is: Argument of type '(item: IFormattedNode) => string' is not assignable to parameter of type 'Accessor<NodeObject, string>'.   Type '(item: IFormattedNode) => string' is not assignable to type '(obj: NodeObject) => string'.     Types of parameters 'item' and 'obj' are incompatible.       Type '{ id?: string | number | undefined; x?: number | undefined; y?: number | undefined; z?: number | undefined; vx?: number | undefined; vy?: number | undefined; vz?: number | undefined; fx?: number | undefined; fy?: number | undefined; fz?: number | undefined; }' is missing the following properties from type 'IFormattedNode': name, group, relationType, relationDegree, relationDetail

RaulPROP commented 4 years ago

I use this format:

const red = 255; // between 0 and 255
const green = 120; // between 0 and 255
const blue = 130; // between 0 and 255
const alpha = 0.66; // between 0 and 1
return `rgba(${red}, ${blue}, ${green}, ${alpha})`;
lancegliser commented 4 years ago

That's not the question. Sorry Raul. I already manage colors well, using tinycolor2. Thanks for jumping in to help just the same.

The issue is that Typescript itself is upset with the idea of using this line of code: .nodeColor(getNodeColor);

I've added the typescript error I'm getting to the original post.

vasturiano commented 4 years ago

@lancegliser it appears the issue is that your IFormattedNode type is not compatible with the library's NodeObject type: https://github.com/vasturiano/three-forcegraph/blob/master/src/index.d.ts#L8-L19

You didn't include the definition of IFormaattedNode so it's hard to say why, but is it apparent why the two types are incompatible?

lancegliser commented 4 years ago

Just as a basic idea for discussion:

export interface IFormattedNode {
    id: string;
    name: string;
    relationType: number;
    relationDegree: number;
    relationDetail: string;
    address?: string;
    latitude?: number;
    longitude?: number;
}

But it's not meant to be compatible exactly. The actual functionality of getNodeColor() does work. It returns the object as expected so IFormattedNode is correct in that regard.

The function, nodeColor() takes one argument of type function. That function includes what looks like it should be a TypeScript generic. So it should allow for me to specify the type of object we'll be returning from the function mixed with the introduced properties.

It's a chain of generics that runs:

// The input function, type of NodeAccessor<string>. It *looks* like string is meant to be a generic.
nodeColor(colorAccessor: NodeAccessor<string>): ChainableInstance;
// Because NodeAccessor clearly states it's got a generic:
type NodeAccessor<T> = Accessor<NodeObject, T>;
// Which flows through to another generic:
type Accessor<In, Out> = Out | string | ((obj: In) => Out);
// And it's that Out portion of "((obj: In) => Out)" function mode I'm trying to get.
Alexithemia commented 4 years ago

I'm using typescript as well via angular. I am currently using .nodeColor((node: any) => node.color) in my project until I am finished with all the capabilities I need and will make a typing file for it once it's finalized.

The node provided by .nodeColor is the libaries' so you could use the typing for that, or use any temporarily and log it out and see what all you will need to model. Whatever function you use it just needs to return a string with any of the typical color formats.