Chart.js Types of property 'type' are incompatible. Type 'string' is not assignable to type '"line" | "bar" | "scatter"

Tatyana Molchanova picture Tatyana Molchanova · Apr 12, 2021 · Viewed 7.3k times · Source
client:159 src/app/analytics-page/analytics-page.component.ts:211:26 - error TS2345: Argument of type '{ type: string; options: { responsive: boolean; }; data: { labels: string[]; datasets: { label: string; data: number[]; borderColor: string; steppedLine: boolean; fill: boolean; }[]; }; }' is not assignable to parameter of type 'ChartConfiguration<"line" | "bar" | "scatter" | "bubble" | "pie" | "doughnut" | "polarArea" | "radar", number[], string>'.
  Types of property 'type' are incompatible.
    Type 'string' is not assignable to type '"line" | "bar" | "scatter" | "bubble" | "pie" | "doughnut" | "polarArea" | "radar"'.

211       new Chart(gainCtx, createChartConfig(gainConfig))
import {AfterViewInit, Component, ElementRef, OnDestroy, ViewChild} from '@angular/core'
import {AnalyticsService} from '../shared/services/analytics.service'
import {AnalyticsPage, ChartConfig} from '../shared/interfaces'
import {Chart} from 'chart.js'
import {Subscription} from 'rxjs'

@Component({
  selector: 'app-analytics-page',
  templateUrl: './analytics-page.component.html',
  styleUrls: ['./analytics-page.component.scss']
})
export class AnalyticsPageComponent implements AfterViewInit, OnDestroy {

  @ViewChild('gain') gainRef!: ElementRef
  @ViewChild('order') orderRef!: ElementRef

  aSub!: Subscription
  average!: number
  pending = true

  constructor(private service: AnalyticsService) {
  }

  ngAfterViewInit() {
    const gainConfig: any = {
      label: 'Выручка',
      color: 'rgb(255, 99, 132)'
    }

    const orderConfig: any = {
      label: 'Заказы',
      color: 'rgb(54, 162, 235)'
    }

    this.aSub = this.service.getAnalytics().subscribe((data: AnalyticsPage) => {
      this.average = data.average

      gainConfig.labels = data.chart.map(item => item.label)
      gainConfig.data = data.chart.map(item => item.gain)

      orderConfig.labels = data.chart.map(item => item.label)
      orderConfig.data = data.chart.map(item => item.order)

      // **** Gain ****
      // gainConfig.labels.push('08.05.2018')
      // gainConfig.labels.push('09.05.2018')
      // gainConfig.data.push(1500)
      // gainConfig.data.push(700)
      // **** /Gain ****

      // **** Order ****
      // orderConfig.labels.push('08.05.2018')
      // orderConfig.labels.push('09.05.2018')
      // orderConfig.data.push(8)
      // orderConfig.data.push(2)
      // **** /Order ****

      const gainCtx = this.gainRef.nativeElement.getContext('2d')
      const orderCtx = this.orderRef.nativeElement.getContext('2d')
      gainCtx.canvas.height = '300px'
      orderCtx.canvas.height = '300px'

      new Chart(gainCtx, createChartConfig(gainConfig))
      new Chart(orderCtx, createChartConfig(orderConfig))

      this.pending = false
    })
  }

  ngOnDestroy() {
    if (this.aSub) {
      this.aSub.unsubscribe()
    }
  }

}


function createChartConfig({labels, data, label, color}: ChartConfig) {
  return {
    type: 'line',
    options: {
      responsive: true
    },
    data: {
      labels,
      datasets: [
        {
          label, data,
          borderColor: color,
          steppedLine: false,
          fill: false
        }
      ]
    }
  }
}

The problem is in type: 'line',. Chart.js is not working, it not work with any type, throws error.

Answer

James Lawruk picture James Lawruk · Apr 19, 2021

Looks like your TypeScript compiler is complaining because the chart type property is a specific type rather than a string.

Option 1:

Import ChartType and cast type as ChartType.

import {  Chart, ChartType, ...} from 'chart.js';

 ...

function createChartConfig({labels, data, label, color}: ChartConfig) {
  return {
    type: 'line' as ChartType,
    options: {
   ...

Option 2: (The easier/hacky way)

Cast the entire config as any.

new Chart(gainCtx, createChartConfig(gainConfig) as any);

In any case, you will need to import and register the needed controllers, elements, scales, etc. Registering registerables registers everything, but it is better to register only what you require for your specific chart. See the Integration instructions for more information.

import { Chart, registerables } from 'chart.js';
...
Chart.register(...registerables);