]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Strong chart object and properties typing (#7782)
authoremmcbd <42184090+emmcbd@users.noreply.github.com>
Sat, 12 Sep 2020 00:18:21 +0000 (02:18 +0200)
committerGitHub <noreply@github.com>
Sat, 12 Sep 2020 00:18:21 +0000 (20:18 -0400)
* Strong chart object and chart creation typing
* Handle mixed charts
* Add documentation

docs/docs/developers/charts.md
types/core/index.d.ts
types/interfaces.d.ts

index 385132b8ea53db85ec7b24308ef977a20b37786a..360ec616e25c298843143ba9007949e3e4be57ba 100644 (file)
@@ -150,3 +150,33 @@ new Chart(ctx, {
     options: options
 });
 ```
+
+## TypeScript Typings
+
+If you want your new chart type to be statically typed, you must provide a `.d.ts` TypeScript declaration file. Chart.js provides a way to augment built-in types with user-defined ones, by using the concept of "declaration merging".
+
+There are three main declarations that can be augmented when adding a new chart type:
+
+* `ChartTypeEnum` enumeration must contain an entry for the new type.
+* `IChartDatasetRegistry` must contains the dataset options for the new type, either by extending `IChartDatasetBase` or an existing entry in `IChartDatasetRegistry`.
+* `IChartOptionsRegistry` must contains the chart options for the new type, either by extending `IChartOptionsBase` or an existing entry in `IChartOptionsRegistry`.
+
+For example, to provide typings for a new chart type that extends from a bubble chart, you would add a `.d.ts` containing:
+
+```javascript
+import { IChartDatasetRegistry, IChartOptionsRegistry } from 'chart.js'
+
+declare module 'chart.js' {
+    enum ChartTypeEnum {
+        derivedBubble = 'derivedBubble'
+    }
+
+    interface IChartDatasetRegistry<DATA extends unknown[]> {
+        derivedBubble: IChartDatasetRegistry<DATA>['bubble']
+    }
+
+    interface IChartOptionsRegistry {
+        derivedBubble: IChartOptionsRegistry['bubble']
+    }
+}
+```
index 1739fcde71cf2d245a524016107c1b03e643044e..483634438561879a7bbc90ea53ffa4432a6ad9c8 100644 (file)
@@ -10,7 +10,7 @@ import {
   TimeUnit,
   IEvent,
 } from './interfaces';
-import { IChartDataset, IChartConfiguration, ConfigurationOptions, ConfigurationData, IChartType } from '../interfaces';
+import { IChartDataset, IChartConfiguration, IChartType } from '../interfaces';
 
 export interface IDateAdapter {
   /**
@@ -232,16 +232,12 @@ export interface IParsingOptions {
     | false;
 }
 
-export interface Chart<
-  T = unknown,
-  L = string,
-  C extends IChartConfiguration<IChartType, T, L> = IChartConfiguration<IChartType, T, L>
-> {
+export interface Chart<TYPE extends IChartType = IChartType, DATA extends unknown[] = unknown[], LABEL = string> {
   readonly platform: BasePlatform;
   readonly id: string;
   readonly canvas: HTMLCanvasElement;
   readonly ctx: CanvasRenderingContext2D;
-  readonly config: C;
+  readonly config: IChartConfiguration<TYPE, DATA, LABEL>
   readonly width: number;
   readonly height: number;
   readonly aspectRatio: number;
@@ -252,8 +248,8 @@ export interface Chart<
   readonly scale: Scale | undefined;
   readonly attached: boolean;
 
-  data: ConfigurationData<C>;
-  options: ConfigurationOptions<C>;
+  data: IChartConfiguration<TYPE, DATA, LABEL>['data'];
+  options: IChartConfiguration<TYPE, DATA, LABEL>['options'];
 
   clear(): this;
   stop(): this;
@@ -301,10 +297,10 @@ export declare type ChartItem =
 
 export const Chart: {
   prototype: Chart;
-  new <T = unknown, L = string, C extends IChartConfiguration<IChartType, T, L> = IChartConfiguration<IChartType, T, L>>(
+  new <TYPE extends IChartType = IChartType, DATA extends unknown[] = unknown[], LABEL = string>(
     item: ChartItem,
-    config: C
-  ): Chart<T, L, C>;
+    config: IChartConfiguration<TYPE, DATA, LABEL>
+  ): Chart<TYPE, DATA, LABEL>;
 
   readonly version: string;
   readonly instances: { [key: string]: Chart };
index 27239a6e7d8fde07c21ddaa6af52c74b138d7479..d7b2cf7946f266eb33c98fecc92f33ef222e065d 100644 (file)
@@ -37,40 +37,6 @@ export type DeepPartial<T> = T extends {}
     }
   : T;
 
-export type IChartDataset<T = unknown, O = {}> = DeepPartial<IControllerDatasetOptions & IParsingOptions & O> & {
-  data: T[];
-};
-
-export type IBarControllerDataset<T = number> = IChartDataset<T, IBarControllerDatasetOptions>;
-export type ILineControllerDataset<T = IScatterDataPoint> = IChartDataset<
-  T,
-  ILineControllerDatasetOptions & IFillerControllerDatasetOptions
->;
-export type IScatterControllerDataset<T = IScatterDataPoint> = IChartDataset<T, IScatterControllerDatasetOptions>;
-export type IBubbleControllerDataset<T = IBubbleDataPoint> = IChartDataset<T, IBubbleControllerDatasetOptions>;
-export type IPieControllerDataset<T = IPieDataPoint> = IChartDataset<T, IPieControllerDatasetOptions>;
-export type IDoughnutControllerDataset<T = IDoughnutDataPoint> = IChartDataset<T, IDoughnutControllerDatasetOptions>;
-export type IPolarAreaControllerDataset<T = number> = IChartDataset<T, IPolarAreaControllerDatasetOptions>;
-export type IRadarControllerDataset<T = number> = IChartDataset<T, IRadarControllerDatasetOptions>;
-
-export interface IChartData<T = unknown, L = string, DS extends IChartDataset<T> = IChartDataset<T>>
-{
-  labels: L[];
-  datasets: DS[];
-}
-
-export type IChartOptions<O = {}> = DeepPartial<
-  ICoreChartOptions &
-    IParsingOptions &
-    ITooltipChartOptions &
-    ILegendChartOptions &
-    ITitleChartOptions &
-    IChartAnimationOptions &
-    IScaleChartOptions &
-    IElementChartOptions &
-    O
->;
-
 export enum ChartTypeEnum {
   bar = 'bar',
   bubble = 'bubble',
@@ -84,79 +50,111 @@ export enum ChartTypeEnum {
 
 export type IChartType = keyof typeof ChartTypeEnum;
 
-export interface IChartConfiguration<
-  TYPE extends IChartType = IChartType,
-  T = unknown,
-  L = string,
-  DS extends IChartDataset<T> = IChartDataset<T>,
-  O = {}
-> {
-  type: TYPE;
-  data: IChartData<T, L, DS>;
-  options?: IChartOptions<O>;
-  plugins?: IPlugin[];
+export interface IChartDatasetProperties<TYPE extends IChartType, DATA extends unknown[]> {
+  type?: TYPE;
+  data: DATA;
 }
 
-export type IBarControllerConfiguration<T = number, L = string> = IChartConfiguration<
+export type IChartDatasetBase<TYPE extends IChartType, DATA extends unknown[], O> = DeepPartial<
+  IControllerDatasetOptions & IParsingOptions & O
+> & IChartDatasetProperties<TYPE, DATA>;
+
+export type IBarControllerDataset<DATA extends unknown[] = number[]> = IChartDatasetBase<
   'bar',
-  T,
-  L,
-  IBarControllerDataset<T>,
-  IBarControllerChartOptions
+  DATA,
+  IBarControllerDatasetOptions
 >;
-export type ILineControllerConfiguration<T = IScatterDataPoint, L = string> = IChartConfiguration<
+export type ILineControllerDataset<DATA extends unknown[] = IScatterDataPoint[]> = IChartDatasetBase<
   'line',
-  T,
-  L,
-  ILineControllerDataset<T>,
-  ILineControllerChartOptions
+  DATA,
+  ILineControllerDatasetOptions & IFillerControllerDatasetOptions
 >;
-export type IScatterControllerConfiguration<T = IScatterDataPoint, L = string> = IChartConfiguration<
+export type IScatterControllerDataset<DATA extends unknown[] = IScatterDataPoint[]> = IChartDatasetBase<
   'scatter',
-  T,
-  L,
-  IScatterControllerDataset<T>,
-  IScatterControllerChartOptions
+  DATA,
+  IScatterControllerDatasetOptions
 >;
-export type IBubbleControllerConfiguration<T = IBubbleDataPoint, L = string> = IChartConfiguration<
+export type IBubbleControllerDataset<DATA extends unknown[] = IBubbleDataPoint[]> = IChartDatasetBase<
   'bubble',
-  T,
-  L,
-  IBubbleControllerDataset<T>
+  DATA,
+  IBubbleControllerDatasetOptions
 >;
-export type IPieControllerConfiguration<T = IPieDataPoint, L = string> = IChartConfiguration<
+export type IPieControllerDataset<DATA extends unknown[] = IPieDataPoint[]> = IChartDatasetBase<
   'pie',
-  T,
-  L,
-  IPieControllerDataset<T>,
-  IPieControllerChartOptions
+  DATA,
+  IPieControllerDatasetOptions
 >;
-export type IDoughnutControllerConfiguration<T = IDoughnutDataPoint, L = string> = IChartConfiguration<
+export type IDoughnutControllerDataset<DATA extends unknown[] = IDoughnutDataPoint[]> = IChartDatasetBase<
   'doughnut',
-  T,
-  L,
-  IDoughnutControllerDataset<T>,
-  IDoughnutControllerChartOptions
+  DATA,
+  IDoughnutControllerDatasetOptions
 >;
-export type IPolarAreaControllerConfiguration<T = number, L = string> = IChartConfiguration<
+export type IPolarAreaControllerDataset<DATA extends unknown[] = number[]> = IChartDatasetBase<
   'polarArea',
-  T,
-  L,
-  IPolarAreaControllerDataset<T>,
-  IPolarAreaControllerChartOptions
+  DATA,
+  IPolarAreaControllerDatasetOptions
 >;
-export type IRadarControllerConfiguration<T = number, L = string> = IChartConfiguration<
+export type IRadarControllerDataset<DATA extends unknown[] = number[]> = IChartDatasetBase<
   'radar',
-  T,
-  L,
-  IRadarControllerDataset<T>,
-  IRadarControllerChartOptions
+  DATA,
+  IRadarControllerDatasetOptions
 >;
 
-export type ConfigurationOptions<O> = O extends IChartConfiguration<IChartType, infer T, infer L, infer DS, infer O> ? O : never;
-export type ConfigurationData<O> = O extends IChartConfiguration<IChartType, infer T, infer L, infer DS, infer O>
-  ? IChartData<T, L, DS>
-  : never;
-export type ConfigurationDataset<O> = O extends IChartConfiguration<IChartType, infer T, infer L, infer DS, infer O>
-  ? DS
-  : never;
+export interface IChartDatasetRegistry<DATA extends unknown[]> {
+  bar: IBarControllerDataset<DATA>;
+  line: ILineControllerDataset<DATA>;
+  scatter: IScatterControllerDataset<DATA>;
+  bubble: IBubbleControllerDataset<DATA>;
+  pie: IPieControllerDataset<DATA>;
+  doughnut: IDoughnutControllerDataset<DATA>;
+  polarArea: IPolarAreaControllerDataset<DATA>;
+  radar: IRadarControllerDataset<DATA>;
+}
+
+export type IChartDataset<T extends unknown[] = unknown[]> = IChartDatasetRegistry<T>[keyof IChartDatasetRegistry<T>]
+
+export interface IChartData<
+  TYPE extends IChartType = IChartType,
+  DATA extends unknown[] = unknown[],
+  LABEL = string
+> {
+  labels: LABEL[];
+  // IChartDatasetProperties is repeated here in order to help the compiler to infer the generic types
+  datasets: (IChartDatasetProperties<TYPE, DATA> & IChartDatasetRegistry<DATA>[TYPE])[];
+}
+
+export type IChartOptionsBase<O> = DeepPartial<
+  ICoreChartOptions &
+    IParsingOptions &
+    ITooltipChartOptions &
+    ILegendChartOptions &
+    ITitleChartOptions &
+    IChartAnimationOptions &
+    IScaleChartOptions &
+    IElementChartOptions &
+    O
+>;
+
+export interface IChartOptionsRegistry {
+  bar: IChartOptionsBase<IBarControllerChartOptions>;
+  line: IChartOptionsBase<ILineControllerChartOptions>;
+  scatter: IChartOptionsBase<IScatterControllerChartOptions>;
+  bubble: IChartOptionsBase<{}>;
+  pie: IChartOptionsBase<IPieControllerChartOptions>;
+  doughnut: IChartOptionsBase<IDoughnutControllerChartOptions>;
+  polarArea: IChartOptionsBase<IPolarAreaControllerChartOptions>;
+  radar: IChartOptionsBase<IRadarControllerChartOptions>;
+}
+
+export type IChartOptions = IChartOptionsRegistry[keyof IChartOptionsRegistry]
+
+export interface IChartConfiguration<
+  TYPE extends IChartType = IChartType,
+  DATA extends unknown[] = unknown[],
+  LABEL = string
+> {
+  type: TYPE;
+  data: IChartData<TYPE, DATA, LABEL>;
+  options?: IChartOptionsRegistry[TYPE];
+  plugins?: IPlugin[];
+}