javascript - Argument av typen '[string, string] fel? (i Angular och d3)


Jag använder d3 (version 4) med Angular 5 och stöter på några fel som jag inte kan hitta mycket information om. I min name.component.ts har jag min d3-kod och får fel under vissa rader.

var x = d3.scaleTime()
  .rangeRound([0, width])
  .domain(d3.extent(this.data, function (d) { return d.date; }));

var y = d3.scaleLinear()
  .rangeRound([height, 0])
  .domain(d3.extent(this.data, function (d) { return d.ratio; }));

För båda dessa rader får jag den röda linjen under allt inom domänen (d3.extent(this.data, function (d) { return d.ratio; })).

Felet är:

Argument of type '[string, string] | [undefined, undefined]' is not 
assignable to parameter of type '(number | Date | { valueOf(): number;}) []'.
Type '[string, string]' is not assignable to type '(number | Date | 
{valueOf(): number; })[]'.
Types of property 'push' are incompatible.
  Type '(...items: string[]) => number' is not assignable to type 
'(...items: (number | Date | { valueOf(): number; })[]) => number'.
    Types of parameters 'items' and 'items' are incompatible.
      Type 'number | Date | { valueOf(): number; }' is not assignable 
to type 'string'.
        Type 'number' is not assignable to type 'string'.

Min gissning är att det finns en konflikt i datatypen, men kan inte lista ut det. Några tankar?

Om detta hjälper, här är hela min .ts-fil:

import { Component, OnInit, Input } from '@angular/core';
import { DataService } from '../data.service';
import { Http } from '@angular/http';
import * as d3 from 'd3';

@Component({
 selector: 'app-name',
 templateUrl: './name.component.html',
 styleUrls: ['./name.component.css']
})
export class Name implements OnInit {
  @Input() site1;

constructor(private _dataService: DataService, private http: Http) { }

date: Date;
dates: any;
value: Number;
eachobj: any;
data: any;
average: any;
values: any;
name: any;
ngOnInit() {

this.data = this.site1
this.dates = Object.keys(this.data.historical_data)
this.values = Object.values(this.data.historical_data)
this.values.forEach((obj, i) => obj.date = this.dates[i]);
this.data = this.values        


var svg = d3.selectAll("#watertemp_graph"),
  margin = { top: 20, right: 20, bottom: 30, left: 0 },
  width = +svg.attr("width") - margin.left - margin.right,
  height = +svg.attr("height") - margin.top - margin.bottom
var parse = d3.timeParse("%Y-%m-%d")
var first = this.data[0].date
var last = this.data[(this.data.length) - 1].date

var g = svg.append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var baseValue = +this.data[0].avg_water_temp;
this.data.forEach(function (d) {
  d.date = parse(d.date);
  d.ratio = +(d.avg_water_temp / baseValue);
});

var x = d3.scaleTime()
  .rangeRound([0, width])
  .domain(d3.extent(this.data, function (d) { return d.date; }));
//ERROR

var y = d3.scaleLinear()
  .rangeRound([height, 0])
  .domain(d3.extent(this.data, function (d) { return d.ratio; }));
//ERROR

var line = d3.line()
  .x(function (d) { return x(d['date']); })
  .y(function (d) { return y(d['ratio']); });


// plot first and last dates on x axis
svg.append('g')
  .attr("class", "axis--x")
  .append("text")
  .attr("fill", "#000")
  .attr("x", (width / 2) - 80)
  .attr("y", height + 40)
  .text(first)
  .style("font-size", "09")
  .style("font-family", "Roboto")
  .style('fill', '#5a5a5a');
svg.append('g')
  .attr("class", "axis--x")
  .append("text")
  .attr("fill", "#000")
  .attr("x", (width / 2) + 45)
  .attr("y", height + 40)
  .text(last)
  .style("font-size", "09")
  .style("font-family", "Roboto")
  .style('fill', '#5a5a5a');


g.append("g")
  .call(d3.axisLeft(y))
  .remove();

g.append("path")
  .datum(this.data)
  .attr("fill", "none")
  .attr("stroke", "#26aae2")
  .attr("stroke-width", 1.5)
  .attr("d", line);

 }

}

Svar #1

d3.extent har två överlagringar som tar två parametrar:

export function extent<T>(array: ArrayLike<T>,
  accessor: (datum: T, index: number, array: ArrayLike<T>) => string | undefined | null):
  [string, string] | [undefined, undefined];

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

TypeScript löser alltid ett anrop till den första matchande överlagringen, och eftersom this.data deklareras som typen any, kan TypeScript inte utesluta att den första överlagringen matchar. Det är härifrån [string, string] kommer. Om du anger en mer exakt typ för this.data, bör det första anropet lösas till den andra överlagringen och returtypen bör bli som förväntat [Date, Date] | [undefined, undefined]. Du kommer fortfarande behöva en typassertion för att försäkra att resultatet är [Date, Date] och inte [undefined, undefined]; jag känner inte till något rimligt sätt att göra detta med inskränkning. Så din kod skulle se ut så här:

var x = d3.scaleTime()
  .rangeRound([0, width])
  .domain(<[Date, Date]>d3.extent(this.data, function (d) { return d.date; }));

Eftersom du behöver typen av försäkran kan du lämna this.data som any, även om det i allmänhet skulle vara bättre praxis att ge det en korrekt typ. Liknande kommentarer gäller för det andra anropet till d3.extent.

Relaterade artiklar