diff --git a/types/index.esm.d.ts b/types/index.esm.d.ts index b5fb8e5c865..370ff849550 100644 --- a/types/index.esm.d.ts +++ b/types/index.esm.d.ts @@ -12,7 +12,7 @@ * } */ -import { DeepPartial, DistributiveArray } from './utils'; +import { DeepPartial, DistributiveArray, UnionToIntersection } from './utils'; import { TimeUnit } from './adapters'; import { AnimationEvent } from './animation'; @@ -29,20 +29,20 @@ export { Element } from './element'; export { ChartArea, Point } from './geometric'; export { LayoutItem, LayoutPosition } from './layout'; -export interface ScriptableContext { +export interface ScriptableContext { active: boolean; - chart: Chart; + chart: UnionToIntersection>; dataIndex: number; - dataset: ChartDataset; + dataset: UnionToIntersection>; datasetIndex: number; - parsed: TParsedData; + parsed: UnionToIntersection>; raw: unknown; } -export type Scriptable = T | (TType extends ChartType ? { [TT in TType]: ((ctx: ScriptableContext>) => T) }[TType] : ((ctx: TType) => T)); -export type ScriptableOptions = { [P in keyof T]: Scriptable }; -export type ScriptableAndArray = readonly T[] | Scriptable; -export type ScriptableAndArrayOptions = { [P in keyof T]: ScriptableAndArray }; +export type Scriptable = T | ((ctx: TContext) => T); +export type ScriptableOptions = { [P in keyof T]: Scriptable }; +export type ScriptableAndArray = readonly T[] | Scriptable; +export type ScriptableAndArrayOptions = { [P in keyof T]: ScriptableAndArray }; export interface ParsingOptions { /** @@ -92,8 +92,8 @@ export interface ControllerDatasetOptions extends ParsingOptions { export interface BarControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions { + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> { /** * The ID of the x axis to plot this dataset on. */ @@ -151,8 +151,8 @@ export const BarController: ChartComponent & { export interface BubbleControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions {} + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> {} export interface BubbleDataPoint { /** @@ -179,10 +179,10 @@ export const BubbleController: ChartComponent & { export interface LineControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions, - ScriptableOptions, - ScriptableOptions { + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions>, + ScriptableOptions>, + ScriptableOptions> { /** * The ID of the x axis to plot this dataset on. */ @@ -237,8 +237,8 @@ export const ScatterController: ChartComponent & { export interface DoughnutControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions { + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> { /** * Sweep to allow arcs to cover. @@ -285,13 +285,13 @@ export interface DoughnutControllerChartOptions { * String ending with '%' means percentage, number means pixels. * @default 50 */ - cutout: Scriptable; + cutout: Scriptable>; /** * The outer radius of the chart. String ending with '%' means percentage of maximum radius, number means pixels. * @default '100%' */ - radius: Scriptable; + radius: Scriptable>; /** * Starting angle to draw arcs from. @@ -361,10 +361,10 @@ export const PolarAreaController: ChartComponent & { export interface RadarControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableOptions, - ScriptableOptions, - ScriptableOptions, - ScriptableOptions { + ScriptableOptions>, + ScriptableOptions>, + ScriptableOptions>, + ScriptableOptions> { /** * The ID of the x axis to plot this dataset on. */ @@ -1432,7 +1432,7 @@ export interface CoreChartOptions extends ParsingOption onClick(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; layout: { - padding: Scriptable; + padding: Scriptable>; }; } @@ -1474,30 +1474,30 @@ export type AnimationSpec = { * The number of milliseconds an animation takes. * @default 1000 */ - duration: Scriptable; + duration: Scriptable>; /** * Easing function to use * @default 'easeOutQuart' */ - easing: Scriptable; + easing: Scriptable>; /** * Running animation count + FPS display in upper left corner of the chart. * @default false */ - debug: Scriptable; + debug: Scriptable>; /** * Delay before starting the animations. * @default 0 */ - delay: Scriptable; + delay: Scriptable>; /** * If set to true, the animations loop endlessly. * @default false */ - loop: Scriptable; + loop: Scriptable>; } export type AnimationsSpec = { @@ -1514,11 +1514,11 @@ export type AnimationsSpec = { /** * Start value for the animation. Current value is used when undefined */ - from: Scriptable; + from: Scriptable>; /** * */ - to: Scriptable; + to: Scriptable>; } } diff --git a/types/tests/scriptable.ts b/types/tests/scriptable.ts index 7fde9acb2eb..5a6dea95745 100644 --- a/types/tests/scriptable.ts +++ b/types/tests/scriptable.ts @@ -1,21 +1,22 @@ -import { Scriptable } from '../index.esm'; +import { ChartType, Scriptable, ScriptableContext } from '../index.esm'; interface test { - pie?: Scriptable, - line?: Scriptable, - testA?: Scriptable - testB?: Scriptable - testC?: Scriptable + pie?: Scriptable>, + line?: Scriptable>, + testA?: Scriptable> + testB?: Scriptable> + testC?: Scriptable> + testD?: Scriptable> } -const pieScriptable: Scriptable = (ctx) => ctx.parsed; -const lineScriptable: Scriptable = (ctx) => ctx.parsed.x + ctx.parsed.y; - export const testImpl: test = { pie: (ctx) => ctx.parsed, line: (ctx) => ctx.parsed.x + ctx.parsed.y, - testA: pieScriptable, - testB: lineScriptable, - // @FIXME ts-expect-error combined type should not be any - testC: (ctx) => ctx.fail + testA: (ctx) => ctx.parsed, + testB: (ctx) => ctx.parsed.x + ctx.parsed.y, + // @ts-expect-error combined type should not be any + testC: (ctx) => ctx.fail, + // combined types are intersections and permit invalid usage + testD: (ctx) => ctx.parsed + ctx.parsed.x + ctx.parsed.r + ctx.parsed._custom.barEnd }; + diff --git a/types/tests/test_instance_assignment.ts b/types/tests/test_instance_assignment.ts index cfcbd855a1b..4f798650fe6 100644 --- a/types/tests/test_instance_assignment.ts +++ b/types/tests/test_instance_assignment.ts @@ -5,7 +5,7 @@ const chart = new Chart('id', { data: { labels: [], datasets: [{ - data: [], + data: [{ x: 0, y: 1 }], pointRadius: (ctx) => ctx.parsed.x, }] }, @@ -18,3 +18,6 @@ interface Context { export const ctx: Context = { chart: chart }; + +// @ts-expect-error Type '{ x: number; y: number; }[]' is not assignable to type 'number[]'. +export const dataArray: number[] = chart.data.datasets[0].data; diff --git a/types/utils.d.ts b/types/utils.d.ts index 6cfbd7d85d5..32b4fc1d5ad 100644 --- a/types/utils.d.ts +++ b/types/utils.d.ts @@ -13,3 +13,6 @@ export type DeepPartial = T extends Function type _DeepPartialObject = { [P in keyof T]?: DeepPartial }; export type DistributiveArray = T extends unknown ? T[] : never + +// From https://stackoverflow.com/a/50375286 +export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;