javascript - Selectarea tipurilor în Typescript, suprasarcina funcțiilor D3.js și tipul de returnare


În prezent lucrez cu d3.js, React și TypeScript și am unele probleme în a înțelege cel mai bun mod de a specifica manual suprasarcina funcției și de a elimina posibilitatea unui rezultat returnat nedefinit.

În exemplul de mai jos, încerc să utilizez extent și să returnez un [Date, Date] folosind o funcție accessor cu următorul tip.

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

Exemplu de utilizare:

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

Problema este că primesc acest mesaj de eroare

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

Cred că acest lucru se datorează faptului că pachetul DefinitelyTyped d3 are următoarea definiție.

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];

Rețineți că tipul Window nu permite o dată nedefinită.

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

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

Am văzut alte răspunsuri ca cele de mai jos care îți sugerează să verifici pentru undefined și să specifici o valoare implicită, dar nu sunt sigur cum să fac asta și să folosesc în continuare o funcție accessor care este transmisă prin props unui component copil.

React, Typescript, d3js, Obținerea erorii 'Niciun suprasarcină nu corespunde acestei apelări'

Există o metodă corectă de a forța o suprasarcină specifică și, de asemenea, de a elimina posibilitatea unui rezultat nedefinit atunci când se utilizează un accessor care este transmis ca parte a proprietăților?

Răspuns #1

Am întâmpinat o problemă similară cu cod similar și iată cum am rezolvat-o:

interface Entry {
  time: Date
}

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

În cazul tău, presupun că ceva de genul acesta ar trebui să funcționeze:

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