From: emmcbd <42184090+emmcbd@users.noreply.github.com> Date: Mon, 14 Sep 2020 13:57:00 +0000 (+0200) Subject: Strong typings for scales and datasets in options (#7791) X-Git-Tag: v3.0.0-beta.2~1^2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5853a46b49a19464b8840ab19ec3e9015f45cb7;p=thirdparty%2FChart.js.git Strong typings for scales and datasets in options (#7791) --- diff --git a/docs/docs/developers/charts.md b/docs/docs/developers/charts.md index 360ec616e..dfe8939dd 100644 --- a/docs/docs/developers/charts.md +++ b/docs/docs/developers/charts.md @@ -158,25 +158,20 @@ If you want your new chart type to be statically typed, you must provide a `.d.t 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`. +* `IChartTypeRegistry` must contains the declarations for the new type, either by extending an existing entry in `IChartTypeRegistry` or by creating a new one. 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' +import { IChartTypeRegistry } from 'chart.js' declare module 'chart.js' { enum ChartTypeEnum { derivedBubble = 'derivedBubble' } - interface IChartDatasetRegistry { - derivedBubble: IChartDatasetRegistry['bubble'] - } - - interface IChartOptionsRegistry { - derivedBubble: IChartOptionsRegistry['bubble'] + interface IChartTypeRegistry { + derivedBubble: IChartTypeRegistry['bubble'] } } ``` diff --git a/types/controllers/index.d.ts b/types/controllers/index.d.ts index 8b8890633..a9189fec6 100644 --- a/types/controllers/index.d.ts +++ b/types/controllers/index.d.ts @@ -12,7 +12,6 @@ import { IPointPrefixedOptions, IRectangleOptions, } from '../elements'; -import { ICategoryScaleType, ILinearScaleType, IRadialLinearScaleType } from '../scales'; export interface IControllerDatasetOptions { /** @@ -80,10 +79,6 @@ export interface IBarControllerDatasetOptions } export interface IBarControllerChartOptions { - scales: { - _index_: ICategoryScaleType; - _value_: ILinearScaleType; - }; } export interface BarController extends DatasetController {} @@ -169,12 +164,7 @@ export interface IScatterDataPoint { y: number; } -export interface IScatterControllerChartOptions extends ILineControllerChartOptions { - scales: { - x: ILinearScaleType; - y: ILinearScaleType; - }; -} +export type IScatterControllerChartOptions = ILineControllerChartOptions; export interface ScatterController extends LineController {} export const ScatterController: IChartComponent & { @@ -276,10 +266,6 @@ export interface IPolarAreaControllerChartOptions { */ startAngle: number; - scales: { - r: IRadialLinearScaleType; - }; - animation: IPolarAreaAnimationOptions; } diff --git a/types/core/index.d.ts b/types/core/index.d.ts index 7eff0b254..a497b245a 100644 --- a/types/core/index.d.ts +++ b/types/core/index.d.ts @@ -10,7 +10,15 @@ import { TimeUnit, IEvent, } from './interfaces'; -import { IChartDataset, IChartConfiguration, IChartType } from '../interfaces'; +import { + DefaultDataPoint, + IChartConfiguration, + IChartData, + IChartDataset, + IChartOptions, + IChartType, + IScaleOptions +} from '../interfaces'; export interface IDateAdapter { /** @@ -232,7 +240,11 @@ export interface IParsingOptions { | false; } -export declare class Chart { +export declare class Chart< + TYPE extends IChartType = IChartType, + DATA extends unknown[] = DefaultDataPoint, + LABEL = string +> { readonly platform: BasePlatform; readonly id: string; readonly canvas: HTMLCanvasElement; @@ -248,8 +260,8 @@ export declare class Chart['data']; - options: IChartConfiguration['options']; + data: IChartData; + options: IChartOptions; constructor(item: ChartItem, config: IChartConfiguration); @@ -858,7 +870,7 @@ export interface ITick { major?: boolean; } -export interface IScaleOptions { +export interface ICoreScaleOptions { /** * Controls the axis global visibility (visible when true, hidden when false). When display: 'auto', the axis is visible only if at least one associated dataset is visible. * @default true @@ -932,7 +944,7 @@ export interface IScaleOptions { afterUpdate(axis: Scale): void; } -export interface Scale extends Element<{}, O>, IChartArea { +export interface Scale extends Element<{}, O>, IChartArea { readonly id: string; readonly type: string; readonly ctx: CanvasRenderingContext2D; @@ -1047,7 +1059,7 @@ export interface Scale extends Element< } export const Scale: { prototype: Scale; - new (cfg: any): Scale; + new (cfg: any): Scale; }; export interface IScriptAbleScaleContext { diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index d7b2cf794..29a7e6bcd 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -29,7 +29,13 @@ import { ITitleChartOptions, } from './plugins'; import { IChartAnimationOptions, IParsingOptions, IPlugin } from './core'; -import { IScaleChartOptions } from './scales'; +import { + ILinearScaleOptions, + ILogarithmicScaleOptions, + ICategoryScaleOptions, + IRadialLinearScaleOptions, + ITimeScaleOptions, +} from './scales'; export type DeepPartial = T extends {} ? { @@ -37,6 +43,46 @@ export type DeepPartial = T extends {} } : T; +export type DistributiveArray = T extends unknown ? T[] : never + +export enum ScaleTypeEnum { + linear = 'linear', + logarithmic = 'logarithmic', + category = 'category', + radialLinear = 'radialLinear', + time = 'time', + timeseries = 'timeseries', +} + +export type IScaleType = keyof typeof ScaleTypeEnum; + +export interface ICartesianScaleTypeRegistry { + linear: { + options: ILinearScaleOptions; + }; + logarithmic: { + options: ILogarithmicScaleOptions; + }; + category: { + options: ICategoryScaleOptions; + }; + time: { + options: ITimeScaleOptions; + }; + timeseries: { + options: ITimeScaleOptions; + }; +} + +export interface IRadialScaleTypeRegistry { + radialLinear: { + options: IRadialLinearScaleOptions; + }; +} + +export interface IScaleTypeRegistry extends ICartesianScaleTypeRegistry, IRadialScaleTypeRegistry { +} + export enum ChartTypeEnum { bar = 'bar', bubble = 'bubble', @@ -50,111 +96,119 @@ export enum ChartTypeEnum { export type IChartType = keyof typeof ChartTypeEnum; -export interface IChartDatasetProperties { - type?: TYPE; - data: DATA; +export interface IChartTypeRegistry { + bar: { + chartOptions: IBarControllerChartOptions; + datasetOptions: IBarControllerDatasetOptions; + defaultDataPoint: number; + scales: keyof ICartesianScaleTypeRegistry; + }; + line: { + chartOptions: ILineControllerChartOptions; + datasetOptions: ILineControllerDatasetOptions & IFillerControllerDatasetOptions; + defaultDataPoint: IScatterDataPoint; + scales: keyof ICartesianScaleTypeRegistry; + }; + scatter: { + chartOptions: IScatterControllerChartOptions; + datasetOptions: IScatterControllerDatasetOptions; + defaultDataPoint: IScatterDataPoint; + scales: keyof ICartesianScaleTypeRegistry; + }; + bubble: { + chartOptions: {}; + datasetOptions: IBubbleControllerDatasetOptions; + defaultDataPoint: IBubbleDataPoint; + scales: keyof ICartesianScaleTypeRegistry; + }; + pie: { + chartOptions: IPieControllerChartOptions; + datasetOptions: IPieControllerDatasetOptions; + defaultDataPoint: IPieDataPoint; + scales: keyof ICartesianScaleTypeRegistry; + }; + doughnut: { + chartOptions: IDoughnutControllerChartOptions; + datasetOptions: IDoughnutControllerDatasetOptions; + defaultDataPoint: IDoughnutDataPoint; + scales: keyof ICartesianScaleTypeRegistry; + }; + polarArea: { + chartOptions: IPolarAreaControllerChartOptions; + datasetOptions: IPolarAreaControllerDatasetOptions; + defaultDataPoint: number; + scales: keyof IRadialScaleTypeRegistry; + }; + radar: { + chartOptions: IRadarControllerChartOptions; + datasetOptions: IRadarControllerDatasetOptions; + defaultDataPoint: number; + scales: keyof IRadialScaleTypeRegistry; + }; } -export type IChartDatasetBase = DeepPartial< - IControllerDatasetOptions & IParsingOptions & O -> & IChartDatasetProperties; - -export type IBarControllerDataset = IChartDatasetBase< - 'bar', - DATA, - IBarControllerDatasetOptions ->; -export type ILineControllerDataset = IChartDatasetBase< - 'line', - DATA, - ILineControllerDatasetOptions & IFillerControllerDatasetOptions ->; -export type IScatterControllerDataset = IChartDatasetBase< - 'scatter', - DATA, - IScatterControllerDatasetOptions ->; -export type IBubbleControllerDataset = IChartDatasetBase< - 'bubble', - DATA, - IBubbleControllerDatasetOptions +export type IScaleOptions = DeepPartial< + { [key in IScaleType]: { type: key } & IScaleTypeRegistry[key]['options'] }[SCALES] >; -export type IPieControllerDataset = IChartDatasetBase< - 'pie', - DATA, - IPieControllerDatasetOptions ->; -export type IDoughnutControllerDataset = IChartDatasetBase< - 'doughnut', - DATA, - IDoughnutControllerDatasetOptions ->; -export type IPolarAreaControllerDataset = IChartDatasetBase< - 'polarArea', - DATA, - IPolarAreaControllerDatasetOptions + +export type IDatasetChartOptions = { + [key in TYPE]: { + datasets: IChartTypeRegistry[key]['datasetOptions']; + }; +}; + +export type IScaleChartOptions = { + scales: { + [key: string]: IScaleOptions; + }; +}; + +export type IChartOptions = DeepPartial< + ICoreChartOptions & + IParsingOptions & + ITooltipChartOptions & + ILegendChartOptions & + ITitleChartOptions & + IChartAnimationOptions & + IElementChartOptions & + IDatasetChartOptions & + IScaleChartOptions & + IChartTypeRegistry[TYPE]['chartOptions'] >; -export type IRadarControllerDataset = IChartDatasetBase< - 'radar', - DATA, - IRadarControllerDatasetOptions + +export type DefaultDataPoint = IChartType extends TYPE ? unknown[] : DistributiveArray< + IChartTypeRegistry[TYPE]['defaultDataPoint'] >; -export interface IChartDatasetRegistry { - bar: IBarControllerDataset; - line: ILineControllerDataset; - scatter: IScatterControllerDataset; - bubble: IBubbleControllerDataset; - pie: IPieControllerDataset; - doughnut: IDoughnutControllerDataset; - polarArea: IPolarAreaControllerDataset; - radar: IRadarControllerDataset; +export interface IChartDatasetProperties { + type?: TYPE; + data: DATA; } -export type IChartDataset = IChartDatasetRegistry[keyof IChartDatasetRegistry] +export type IChartDataset< + TYPE extends IChartType = IChartType, + DATA extends unknown[] = DefaultDataPoint +> = DeepPartial< + IParsingOptions & + { [key in IChartType]: { type: key } & IChartTypeRegistry[key]['datasetOptions'] }[TYPE] +> & IChartDatasetProperties; export interface IChartData< TYPE extends IChartType = IChartType, - DATA extends unknown[] = unknown[], + DATA extends unknown[] = DefaultDataPoint, LABEL = string > { labels: LABEL[]; - // IChartDatasetProperties is repeated here in order to help the compiler to infer the generic types - datasets: (IChartDatasetProperties & IChartDatasetRegistry[TYPE])[]; + datasets: IChartDataset[]; } -export type IChartOptionsBase = DeepPartial< - ICoreChartOptions & - IParsingOptions & - ITooltipChartOptions & - ILegendChartOptions & - ITitleChartOptions & - IChartAnimationOptions & - IScaleChartOptions & - IElementChartOptions & - O ->; - -export interface IChartOptionsRegistry { - bar: IChartOptionsBase; - line: IChartOptionsBase; - scatter: IChartOptionsBase; - bubble: IChartOptionsBase<{}>; - pie: IChartOptionsBase; - doughnut: IChartOptionsBase; - polarArea: IChartOptionsBase; - radar: IChartOptionsBase; -} - -export type IChartOptions = IChartOptionsRegistry[keyof IChartOptionsRegistry] - export interface IChartConfiguration< TYPE extends IChartType = IChartType, - DATA extends unknown[] = unknown[], + DATA extends unknown[] = DefaultDataPoint, LABEL = string > { type: TYPE; data: IChartData; - options?: IChartOptionsRegistry[TYPE]; + options?: IChartOptions; plugins?: IPlugin[]; } diff --git a/types/scales/index.d.ts b/types/scales/index.d.ts index 729aaf457..682116743 100644 --- a/types/scales/index.d.ts +++ b/types/scales/index.d.ts @@ -1,6 +1,5 @@ -import { ScriptAbleScale, IScaleOptions, ITick, Scale } from '../core'; +import { ScriptAbleScale, ICoreScaleOptions, ITick, Scale } from '../core'; import { Color, IChartComponent, IFontSpec, TimeUnit } from '../core/interfaces'; -import { DeepPartial } from '../interfaces'; export interface IGridLineOptions { /** @@ -85,7 +84,7 @@ export interface ITickOptions { }; } -export interface ICartesianScaleOptions extends IScaleOptions { +export interface ICartesianScaleOptions extends ICoreScaleOptions { /** * Position of the axis. */ @@ -276,7 +275,7 @@ export type ITimeScaleOptions = ICartesianScaleOptions & { */ round: false | TimeUnit; /** - * If boolean and true and the unit is set to 'week', then the first day of the week will be Monday. Otherwise, it will be Sunday. + * If boolean and true and the unit is set to 'week', then the first day of the week will be Monday. Otherwise, it will be Sunday. * If `number`, the index of the first day of the week (0 - Sunday, 6 - Saturday). * @default false */ @@ -342,7 +341,7 @@ export const TimeSeriesScale: IChartComponent & { new (cfg: any): TimeSeriesScale; }; -export type IRadialLinearScaleOptions = IScaleOptions & { +export type IRadialLinearScaleOptions = ICoreScaleOptions & { animate: boolean; angleLines: { @@ -476,28 +475,3 @@ export const RadialLinearScale: IChartComponent & { prototype: RadialLinearScale; new (cfg: any): RadialLinearScale; }; - -export interface ILinearScaleType extends DeepPartial { - type: 'linear'; -} -export interface ILogarithmicScaleType extends DeepPartial { - type: 'logarithmic'; -} -export interface ICategoryScaleType extends DeepPartial { - type: 'category'; -} -export interface IRadialLinearScaleType extends DeepPartial { - type: 'radialLinear'; -} -export interface ITimeScaleType extends DeepPartial { - type: 'time'; -} -export interface ITimeSeriesScaleType extends DeepPartial { - type: 'timeseries'; -} - -export interface IScaleChartOptions { - scales: { - [key: string]: { type: string } & DeepPartial; - }; -}