Xenyal
Xenyal

Reputation: 2223

Typescript typecast with D3.js

I'm using the example D3 graph shown here. I have the following data object declared here:

interface ID3Data {
  age: string,
  population: number
}

const data: ID3Data[] = [
  { age: "<5", population: 2704659 },
  { age: "5-13", population: 4499890 }
]

and then being consumed in the following:

const pie = d3.pie()
              .value(function(d: any) { return d.population; });

const arc = g.selectAll(".arc")
             .data(pie(data)) // ->>> Specifically this part of the code

Which produces this error:

TypeScript error: Argument of type 'ID3Data[]' is not assignable to parameter of type '(number | { valueOf(): number; })[]'.
  Type 'ID3Data' is not assignable to type 'number | { valueOf(): number; }'.
    Type 'ID3Data' is not assignable to type '{ valueOf(): number; }'.
      Types of property 'valueOf' are incompatible.
        Type '() => Object' is not assignable to type '() => number'.
          Type 'Object' is not assignable to type 'number'.  TS2345

Since it's apparent that d3.pie().value() consumes a very specific type of input data, what am I doing wrong that's receiving the compilation error? Since D3's value function is specific to it's library... is it something that I can override in my typescript code?

Upvotes: 3

Views: 458

Answers (1)

altocumulus
altocumulus

Reputation: 21578

This is the problematic code:

const pie = d3.pie()
              .value(function(d: any) { return d.population; });

Since you did not specify the type of the data you are going to pass to the generator the TypeScript compiler will use the following type definition:

export function pie(): Pie<any, number | { valueOf(): number }>;

That results in the error you witnessed because your type ID3Data obviously does not match number | { valueOf(): number }.

Fortunately, this can easily be cured by using generics to pass the correct type of data while creating the generator:

const pie = d3.pie<ID3Data>()
  .value(function(d) { return d.population; });   // Do not use any for the parameter!

This will have the compiler use the following type definition instead:

export function pie<Datum>(): Pie<any, Datum>;

As you can see the type Datum is now passed on to the Pie interface type.

Upvotes: 2

Related Questions