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

3

10
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.

Dipeptide answered 12/4, 2021 at 12:22 Comment(2)
Try specifying the return type, function createChartConfig({labels, data, label, color}: ChartConfig): ChartConfiguration<"line"> {Selfsustaining
I did as you say and it throws new error: core.js:6162 ERROR Error: "line" is not a registered controller.Dipeptide
V
15

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);
Vassalize answered 19/4, 2021 at 14:50 Comment(0)
M
2

I had a similar error, when Googling the error this SO question came up so I will drop a related solution here.

This is somewhat of a work around, but I was getting this error:

Types of property 'borderJoinStyle' are incompatible.
            Type 'string' is not assignable to type '"miter" | "round" | "bevel" | ((ctx: ScriptableContext<"line">, options: AnyObject) => CanvasLineJoin | undefined) | undefined'.

To resolve the issue I changed my setting from borderJoinStyle: "miter" to borderJoinStyle: "miter" as const.

I was also getting this error:

Types of property 'borderCapStyle' are incompatible.
            Type 'string' is not assignable to type '"butt" | "round" | "square" | ((ctx: ScriptableContext<"line">, options: AnyObject) => CanvasLineCap | undefined) | undefined'.

I made a similar change as above. Changed from borderCapStyle: "round" to borderCapStyle: "round" as const

I found the answer on Github:

https://github.com/apexcharts/react-apexcharts/issues/347#issuecomment-932848265

Materially answered 24/8, 2022 at 4:15 Comment(0)
V
1

First, you need to include the library from chart.js/auto, and not from chart.js.

I wrote about this in more detail in a similar topic here.

To avoid an error, the function for generating configurations createChartConfig() must return data corresponding to the interface signature ChartConfiguration, or a generalization <ChartConfiguration> must be written for the called function. Accordingly, it is also necessary to connect ChartConfiguration from chart.js/auto.

The final working code will look like this:

import { Chart, ChartConfiguration } from 'chart.js/auto'

ngAfterViewInit (): void {
   // .......
   new Chart(gainCtx, <ChartConfiguration>createChartConfig(gainConf)) // with generic
   new Chart(orderCtx, createChartConfig(orderConfig)) // without generic
   // .......
}

function createChartConfig ({ labels, data, label, color}: { labels: string[], data: number[], label: string, color: string }): ChartConfiguration {
  return {
    type: 'line',
    data: {
      labels,
      datasets: [{
        label,
        data,
        borderColor: color,
        // steppedLine: false, // v. 3.x <-- deprecated and was removed
        stepped: false, // v. 4
        fill: false
      }]
    },
    options: {
      responsive: true
    }
  }
}
Valse answered 18/1, 2023 at 14:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.