1

i'm new to Typescript and I stubbled an issue that I have no answer for.

Basically I am trying to feed data to Dygraph chart which takes [Date, number, number,...]. The thing is I receive multiple series of data from my API which has this format [Date, number]. Is there an elegant way in type script to switch from [Date, number][] to [Date, number, number,...] without hard coding it like I did below? I mean it works but it makes me want to vomit. Also even though it is very unlikely I would need more than 7 series in the same graph, I hate the idea that this is limited.

Anyway if you have any idea how I could get around this your help would be greatly appreciated!

export class Datapoint {
  date: Date = new Date()
  value: number | undefined
}

export class DatapointSerie {
  datapoints: Datapoint[] = new Array();
}

export class DygraphData {
  maxSeriesCount = 7
  data: [Date, number | undefined, number | undefined, number | undefined, number | undefined, number | undefined, number | undefined, number | undefined][] = []

  constructor(series: DatapointSerie[]) {
    let seriesCount = Math.min(series.length, this.maxSeriesCount)
    for (let i = 0; i < seriesCount; i++) {
      this.fillSerie(series[i], i)
    }
  }

  fillSerie(serie: DatapointSerie, index: number) {
    switch (index) {
      case 0:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, datapoint.value, undefined, undefined, undefined, undefined, undefined, undefined]))
        break
      case 1:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, undefined, datapoint.value, undefined, undefined, undefined, undefined, undefined]))
        break
      case 2:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, undefined, undefined, datapoint.value, undefined, undefined, undefined, undefined]))
        break
      case 3:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, undefined, undefined, undefined, datapoint.value, undefined, undefined, undefined]))
        break
      case 4:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, undefined, undefined, undefined, undefined, datapoint.value, undefined, undefined]))
        break
      case 5:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, undefined, undefined, undefined, undefined, undefined, datapoint.value, undefined]))
        break
      case 6:
        serie.datapoints.forEach((datapoint) => this.data.push([datapoint.date, undefined, undefined, undefined, undefined, undefined, undefined, datapoint.value]))
        break

      default:
        break
    }
  }
}
g1n93r
  • 11
  • 1
  • `type DateNumberTuple = [Date, ...number[]];` [playground](https://tsplay.dev/WvVXRW) – pilchard Feb 28 '22 at 17:21
  • Can you provide a [mre] with some actual data? You're asking to refactor code that works, so it would be nice to have test cases to make sure the refactoring doesn't change things. The data format looks like `[Date, ...(number | undefined)[]]` to me, but converting from one to the other is ‍♂️. – jcalz Feb 28 '22 at 17:23
  • Like, maybe [this](https://tsplay.dev/Wyb1dw) works? Maybe not? Not sure without data. – jcalz Feb 28 '22 at 17:26
  • But if you want a fixed length tuple conforming to `maxSeriesCount` see: [Typescript: Can I define an n-length tuple type?](https://stackoverflow.com/questions/52489261/typescript-can-i-define-an-n-length-tuple-type). Another quick [playground](https://tsplay.dev/WvVXRW) demonstrating [this answer](https://stackoverflow.com/a/65914848/13762301) `type DateNumberTuple = [Date, ...Tuple];` – pilchard Feb 28 '22 at 17:26
  • Please revise your post title to ask a clear, specific question in sentence format. See [ask]. – isherwood Feb 28 '22 at 17:38

1 Answers1

0

You can use the array spread operator to declare your array:

data: [Date, ...Array<number | undefined>][] = [];

That means any number of elements of type number or undefined may come after the date.

Then filling the series just becomes:

  constructor(series: DatapointSerie[]) {
    series.forEach((ser, index) => {
      for (const pt of ser.datapoints) {
        const res: [Date, ...Array<number | undefined>] = [pt.date];
        res[index + 1] = pt.value;
        this.data.push(res);
      }
    });
  }
Chris Hamilton
  • 9,252
  • 1
  • 9
  • 26