Chart.js
Chart.js copied to clipboard
Typehinting ChartOptions seems broken for pie and doughnut
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
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, {
~~~~~~~~~~~~~
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
.
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'.
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.
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
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<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<...>, 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; }>'.
Version: 4.4.3
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]}
]
}
});
}
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.
Also effects PolarAreaChart as well.