Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typehinting ChartOptions seems broken for pie and doughnut #10896

Closed
DrowningElysium opened this issue Nov 21, 2022 · 9 comments · Fixed by #11521
Closed

Typehinting ChartOptions seems broken for pie and doughnut #10896

DrowningElysium opened this issue Nov 21, 2022 · 9 comments · Fixed by #11521
Labels
type: bug type: types Typescript type changes

Comments

@DrowningElysium
Copy link

DrowningElysium commented Nov 21, 2022

Expected behavior

I type hint ChartOptions or ChartOptions<ChartType> for a function and then pass a typehint of ChartOptions<'pie'> or ChartOptions<'doughnut'> .

Donut.vue:

<template>
    <Base
        :height="height"
        :width="width"
        :chart-options="chartOptions"
        :chart-data="chartData"
        chart-type="doughnut"
    />
</template>

<script setup lang="ts">
import {
    ArcElement,
    Chart,
    ChartData,
    ChartOptions,
    DoughnutController,
    Legend,
    Tooltip,
} from 'chart.js';
import Base from './Base.vue';

Chart.register(DoughnutController, ArcElement, Legend, Tooltip);

interface Props {
    chartData: ChartData<'doughnut', unknown[]>;
    chartOptions: ChartOptions<'doughnut'>;
    width?: number;
    height?: number;
}

withDefaults(
    defineProps<Props>(),
    {
        width: 200,
        height: 200,
    },
);
</script>

The props typehinting in Base.vue:

import {
    Chart,
    ChartData,
    ChartOptions,
    ChartType,
} from 'chart.js';
import {onBeforeUnmount, onMounted, ref, watch} from 'vue';

interface Props {
    chartType: ChartType;
    chartData: ChartData<ChartType, unknown[]>;
    chartOptions: ChartOptions<ChartType>;
    width: number;
    height: number;
    chartId?: number;
}

const props = withDefaults(
    defineProps<Props>(),
    {
        chartId: () => {
            // @ts-ignore this way it's global
            if (!window.chartId) window.chartId = 0;
            // @ts-ignore this way it's global
            return ++window.chartId;
        },
    },
);

Current behavior

I get the following error in vue-tsc:

resources/js/components/chart/Donut.vue:5:9 - error TS2322: Type '_DeepPartialObject<CoreChartOptions<"doughnut"> & ElementChartOptions<"doughnut"> & PluginChartOptions<"doughnut"> & DatasetChartOptions<"doughnut"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.
  Types of property 'animation' are incompatible.
    Type 'false | _DeepPartialObject<false & DoughnutAnimationOptions> | _DeepPartialObject<AnimationSpec<"doughnut"> & { onProgress?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; } & false> | _DeepPartialObject<...> | undefi...' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart$4<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.
      Type '_DeepPartialObject<false & DoughnutAnimationOptions>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart$4<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.

5         :chart-options="chartOptions"
          ~~~~~~~~~~~~~

  resources/js/components/chart/Base.vue:19:5
    19     chartOptions: ChartOptions<ChartType>;
           ~~~~~~~~~~~~
    The expected type comes from property 'chartOptions' which is declared here on type 'ComponentProps<ComponentPublicInstanceConstructor<{ $: ComponentInternalInstance; $data: {}; $props: Partial<{ chartId: number; }> & Omit<Readonly<ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, { ...; }>>> & VNodeProps & AllowedComponentProps & ComponentCustomProps, "chartId">; ... 10 more...'

Reproducible sample

Code provided in current behaviour

Optional extra steps/info to reproduce

No response

Possible solution

I couldn't find the reason why animation seems to not be compatible. However I did notice that in some areas animation is typehinted as:

  • animation: false | DoughnutAnimationOptions;
  • animation: false | PolarAreaAnimationOptions;
  • animation: AnimationSpec<TType>; This might be the cause?
  • Or the next could be the cause too
animation: false | AnimationSpec<TType> & {
    /**
     * Callback called on each step of an animation.
     */
    onProgress?: (this: Chart$4, event: AnimationEvent) => void;
    /**
     * Callback called when all animations are completed.
     */
    onComplete?: (this: Chart$4, event: AnimationEvent) => void;
  };
  • animation: AnimationSpec<TType> | false;

Context

No response

chart.js version

v4.0.1

Browser name and version

No response

Link to your project

No response

@JayOfferdahl
Copy link

JayOfferdahl commented Nov 21, 2022

I ran into a similar issue today when upgrading typescript from 4.8.2 to 4.9.3:

(!) Plugin typescript: @rollup/plugin-typescript TS2322: Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.
  Types of property 'animation' are incompatible.
    Type 'false | _DeepPartialObject<false & DoughnutAnimationOptions> | _DeepPartialObject<AnimationSpec<"pie"> & { onProgress?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; } & false> | _DeepPartialObject<...> | undefined' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart$4<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.
      Type '_DeepPartialObject<false & DoughnutAnimationOptions>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart$4<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart$4<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.
****.tsx: (54:13)

54             chart.current.options = chartOptions
               ~~~~~~~~~~~~~~~~~~~~~

(!) Plugin typescript: @rollup/plugin-typescript TS2322: Type 'Chart$4<"pie", number[], unknown>' is not assignable to type 'Chart$4<keyof ChartTypeRegistry, (number | ScatterDataPoint | [number, number] | BubbleDataPoint | null)[], unknown>'.
  Types of property 'config' are incompatible.
    Type 'ChartConfiguration<"pie", number[], unknown> | ChartConfigurationCustomTypesPerDataset<"pie", number[], unknown>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | ScatterDataPoint | [number, number] | BubbleDataPoint | null)[], unknown> | ChartConfigurationCustomTypesPerDataset<...>'.
      Type 'ChartConfiguration<"pie", number[], unknown>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | ScatterDataPoint | [number, number] | BubbleDataPoint | null)[], unknown> | ChartConfigurationCustomTypesPerDataset<...>'.
        Type 'ChartConfiguration<"pie", number[], unknown>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | ScatterDataPoint | [number, number] | BubbleDataPoint | null)[], unknown>'.
          Types of property 'options' are incompatible.
            Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions> | undefined' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>> | undefined'.
              Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.
****.tsx: (57:13)

57             chart.current = new Chart(canvas.current, {
               ~~~~~~~~~~~~~

@etimberg etimberg added the type: types Typescript type changes label Nov 21, 2022
@ianparkinson
Copy link

ianparkinson commented Jan 8, 2023

I'm also seeing this with chart.js 4.1.2, when upgrading typescript from 4.8.4 to 4.9.4. I see the same error starting from typescript 4.9.1-beta.

I'm also using chartjs-plugin-datalabels. Code like:

    const chartElement: HTMLCanvasElement = ...
    const options: ChartOptions<"pie"> = {}
    this.pieChart = new Chart(chartElement, {
      type: 'pie',
      plugins: [ChartDataLabels],
      data: {datasets: []},
      options: options
    });

..fails with:

       TS2322: Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.
  Types of property 'animation' are incompatible.
    Type 'false | _DeepPartialObject<false & DoughnutAnimationOptions> | _DeepPartialObject<AnimationSpec<"pie"> & { onProgress?: (this: Chart<...>, event: AnimationEvent) => void; onComplete?: (this: Chart<...>, event: AnimationEvent) => void; } & false> | _DeepPartialObject<...>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: (this: Chart<keyof ChartTypeRegistry, (number | ... 2 more ... | BubbleDataPoint)[], unknown>, event: AnimationEvent) => void; onComplete?: (this: Chart<...>, event: AnimationEvent) => void; }>'.
      Type '_DeepPartialObject<false & DoughnutAnimationOptions>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: (this: Chart<keyof ChartTypeRegistry, (number | ... 2 more ... | BubbleDataPoint)[], unknown>, event: AnimationEvent) => void; onComplete?: (this: Chart<...>, event: AnimationEvent) => void; }>'.

There seems to be some interaction with the plugin. If I provide an empty list, or remove the plugins: property altogether, then the problem goes away. The following builds without error:

    const options: ChartOptions<"pie"> = {}
    this.pieChart = new Chart(chartElement, {
      type: 'pie',
      plugins: [],
      data: {datasets: []},
      options: options
    });

The chart itself renders fine if the TS error is suppressed with @ts-ignore.

@princemaple
Copy link

princemaple commented Feb 23, 2023

Still seeing it on 4.2.1, with ts 4.9.5. Errors about config instead of animation in my case though.

error TS2322: Type 'Chart<"pie", number[], string>' is not assignable to type 'Chart<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown>'.
  Types of property 'config' are incompatible.
    Type 'ChartConfiguration<"pie", number[], string> | ChartConfigurationCustomTypesPerDataset<"pie", number[], string>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown> | ChartConfigurationCustomTypesPerDataset<...>'.
      Type 'ChartConfiguration<"pie", number[], string>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown> | ChartConfigurationCustomTypesPerDataset<...>'.
        Type 'ChartConfiguration<"pie", number[], string>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown>'.
          Types of property 'options' are incompatible.
            Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions> | undefined' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>> | undefined'.
              Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.
                Types of property 'animation' are incompatible.
                  Type 'false | _DeepPartialObject<false & DoughnutAnimationOptions> | _DeepPartialObject<AnimationSpec<"pie"> & { onProgress?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; } & false> | _DeepPartialObject<...> | undefined' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.
                    Type '_DeepPartialObject<false & DoughnutAnimationOptions>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.

@reintroducing
Copy link

For me, I just converted a file where I define Chart defaults and this was one that was erroring:

ChartJs.defaults.animation.duration = 0;
Property 'duration' does not exist on type 'false | (AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; })'.

is there any workaround to this? I'm new to TS and this was a bummer.

@KevinFabre-ods
Copy link

KevinFabre-ods commented Aug 1, 2023

This is also the case when you try to create a type guard

export function isDoughnutConfiguration(config: ChartConfiguration): config is ChartConfiguration<'doughnut'> {
    return (config as ChartConfiguration).type === 'doughnut';
}

v3.8.2

@teodorachiosa
Copy link

teodorachiosa commented Jul 23, 2024

Same here, I'm trying to use the cutout property from the doughnut chart:

  chartOptions: ChartOptions<'doughnut'> = {
    cutout: 80
  };

Output:

error TS2322: Type '_DeepPartialObject<CoreChartOptions<"doughnut"> & ElementChartOptions<"doughnut"> & PluginChartOptions<"doughnut"> & DatasetChartOptions<"doughnut"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions & ElementChartOptions & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.

Types of property 'animation' are incompatible.
Type 'false | _DeepPartialObject<false & DoughnutAnimationOptions> | _DeepPartialObject<AnimationSpec<"doughnut"> & { onProgress?: (this: Chart<...>, event: AnimationEvent) => void; onComplete?: (this: Chart<...>, event: AnimationEvent) => void; } & false> | _DeepPartialObject<...>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec & { onProgress?: (this: Chart<keyof ChartTypeRegistry, (number | ... 2 more ... | BubbleDataPoint)[], unknown>, event: AnimationEvent) => void; onComplete?: (this: Chart<...>, event: AnimationEvent) => void; }>'.
Type '_DeepPartialObject<false & DoughnutAnimationOptions>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec & { onProgress?: (this: Chart<keyof ChartTypeRegistry, (number | ... 2 more ... | BubbleDataPoint)[], unknown>, event: AnimationEvent) => void; onComplete?: (this: Chart<...>, event: AnimationEvent) => void; }>'.

Version: 4.4.3

@davidnaumann-bastian
Copy link

Also seeing above error on version 4.4.3, minimal example this this occurs on below:

    return new Chart(this.elementRef, {
      type: 'pie',
      data: {
        labels: ["hi", "bye"],
        datasets: [
          {data: [1, 2]}
        ]
      }
    });
  }

@davidnaumann-bastian
Copy link

davidnaumann-bastian commented Jul 29, 2024

    Type 'ChartConfiguration<"pie", number[], string> | ChartConfigurationCustomTypesPerDataset<"pie", number[], string>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown> | ChartConfigurationCustomTypesPerDataset<...>'.
      Type 'ChartConfiguration<"pie", number[], string>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown> | ChartConfigurationCustomTypesPerDataset<...>'.
        Type 'ChartConfiguration<"pie", number[], string>' is not assignable to type 'ChartConfiguration<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown>'.
          Types of property 'options' are incompatible.
            Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions> | undefined' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>> | undefined'.
              Type '_DeepPartialObject<CoreChartOptions<"pie"> & ElementChartOptions<"pie"> & PluginChartOptions<"pie"> & DatasetChartOptions<"pie"> & ScaleChartOptions<...> & DoughnutControllerChartOptions>' is not assignable to type '_DeepPartialObject<CoreChartOptions<keyof ChartTypeRegistry> & ElementChartOptions<keyof ChartTypeRegistry> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...>>'.
                Types of property 'animation' are incompatible.
                  Type 'false | _DeepPartialObject<false & DoughnutAnimationOptions> | _DeepPartialObject<AnimationSpec<"pie"> & { onProgress?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; } & false> | _DeepPartialObject<...> | undefined' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.
                    Type '_DeepPartialObject<false & DoughnutAnimationOptions>' is not assignable to type 'false | _DeepPartialObject<AnimationSpec<keyof ChartTypeRegistry> & { onProgress?: ((this: Chart<keyof ChartTypeRegistry, (number | ... 3 more ... | null)[], unknown>, event: AnimationEvent) => void) | undefined; onComplete?: ((this: Chart<...>, event: AnimationEvent) => void) | undefined; }> | undefined'.

Seeing same error as reported from user above for both 'pie' and 'doughnut'.

Typescript version: Version 5.4.5

// @ts-expect-error works and renders chart correctly so likely just related to typing.

@davidnaumann-bastian
Copy link

Also effects PolarAreaChart as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug type: types Typescript type changes
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants