Selecting Typescript, D3.js function overload and return type

Viewed 634

I'm currently working with d3.js, React, and Typescript and having some trouble understanding the best way to manually specify the function overload and eliminate the possibility of an undefined return value.

In the example below, I am trying to utilize extent and return a [Date, Date] using an accessor function with the following type.

xAccessor: (datum: Window, index: number, array: Iterable<Window>) => Date

Example Usage:

const xScale = d3.scaleTime()
    .domain(d3.extent<Iterable<Window>, Iterable<Date>>(data, xAccessor))
    .range([0, dimensions.boundedWidth])

The problem is that I get this error message

Argument of type '[string, string] | [undefined, undefined]' is not assignable to parameter of type 'Iterable<number | Date | { valueOf(): number; }>'.

I believe this is because the DefinitelyTyped d3 package has the following definition.

export function extent<T, U extends Numeric>(
    iterable: Iterable<T>,
    accessor: (datum: T, index: number, array: Iterable<T>) => U | undefined | null
): [U, U] | [undefined, undefined];

Note that the Window type does not allow an undefined date.

export interface Window {
    ts: Date;
    high: number;
    low: number;
    open: number;
    close: number;
    volume: number;
}

const dateAccessor = (d: Window) => d.ts

I've seen other answers like below which have you check for undefined and specify a default value, but I'm not sure how to do that and still leverage an accessor function that is passed in by props to a child component.

React, Typescript, d3js, Getting a No overload matches this call

Is there a correct way to force a specific overload and also eliminate the possibility of an undefined result while using an accessor that is passed in as part of the props?

1 Answers

I've faced a similar issue with similar code and this is how I fixed it:

interface Entry {
  time: Date
}

x.domain(d3.extent(entries, (e: Entry): Date => e.time) as [Date, Date])

In your case, I asssume something like this should work:

const xScale = d3.scaleTime()
    .domain(d3.extent<Iterable<Window>, Iterable<Date>>(data, xAccessor) as [Date, Date])
    .range([0, dimensions.boundedWidth])
Related