Skip to content

Commit

Permalink
Merge pull request #1408 from tradingview/extra-typing-test-for-custo…
Browse files Browse the repository at this point in the history
…m-series

Extra typing test for custom series
  • Loading branch information
edew authored Sep 19, 2023
2 parents 6569b3e + 76604b4 commit 8255ab4
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 6 deletions.
5 changes: 3 additions & 2 deletions src/api/iseries-primitive-api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Time } from '../model/horz-scale-behavior-time/types';
import { ISeriesPrimitiveBase } from '../model/iseries-primitive';
import { SeriesOptionsMap, SeriesType } from '../model/series-options';

Expand All @@ -9,7 +10,7 @@ import { ISeriesApi } from './iseries-api';
* a refresh of the chart.
*/
export interface SeriesAttachedParameter<
HorzScaleItem,
HorzScaleItem = Time,
TSeriesType extends SeriesType = keyof SeriesOptionsMap
> {
/**
Expand All @@ -29,6 +30,6 @@ export interface SeriesAttachedParameter<
/**
* Interface for series primitives. It must be implemented to add some external graphics to series.
*/
export type ISeriesPrimitive<HorzScaleItem> = ISeriesPrimitiveBase<
export type ISeriesPrimitive<HorzScaleItem = Time> = ISeriesPrimitiveBase<
SeriesAttachedParameter<HorzScaleItem, SeriesType>
>;
2 changes: 0 additions & 2 deletions src/api/series-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,6 @@ export class SeriesApi<

// actually they can't exist separately
if (dataFirstBarInRange !== null && dataLastBarInRange !== null) {
// result.from = dataFirstBarInRange.time.businessDay || dataFirstBarInRange.time.timestamp;
// result.to = dataLastBarInRange.time.businessDay || dataLastBarInRange.time.timestamp;
result.from = dataFirstBarInRange.originalTime as HorzScaleItem;
result.to = dataLastBarInRange.originalTime as HorzScaleItem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { TickMarkFormatter } from './horz-scale-behavior-time';
import { Time } from './types';

/**
* Extended time scale options for time-base horz scale
* Extended time scale options for time-based horizontal scale
*/
export interface TimeScaleOptions extends HorzScaleOptions {
/**
Expand Down
1 change: 0 additions & 1 deletion src/model/time-scale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { DeepPartial, isInteger, merge } from '../helpers/strict-type-checks';

import { ChartModel } from './chart-model';
import { Coordinate } from './coordinate';
// import { defaultTickMarkFormatter } from './default-tick-mark-formatter';
import { FormattedLabelsCache } from './formatted-labels-cache';
import { IHorzScaleBehavior, InternalHorzScaleItem, InternalHorzScaleItemKey } from './ihorz-scale-behavior';
import { LocalizationOptions } from './localization-options';
Expand Down
108 changes: 108 additions & 0 deletions tests/type-checks/non-time-based-custom-series.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { createChartEx, customSeriesDefaultOptions } from '../../src';
import { CandlestickData, WhitespaceData } from '../../src/model/data-consumer';
import { Time } from '../../src/model/horz-scale-behavior-time/types';
import { CustomData, CustomSeriesPricePlotValues, ICustomSeriesPaneRenderer, ICustomSeriesPaneView, PaneRendererCustomData } from '../../src/model/icustom-series';
import { IHorzScaleBehavior } from '../../src/model/ihorz-scale-behavior';
import { CustomSeriesOptions } from '../../src/model/series-options';

type HorizontalScaleType = number;

interface NonTimeSeriesOptions extends CustomSeriesOptions {
testOption: string;
}

const defaultOptions: NonTimeSeriesOptions = {
...customSeriesDefaultOptions,
testOption: 'hello',
} as const;

interface NonTimeData extends CustomData<HorizontalScaleType> {
priceY: number;
}

class NonTimeSeries implements ICustomSeriesPaneView<HorizontalScaleType, NonTimeData, NonTimeSeriesOptions> {
public priceValueBuilder(plotRow: NonTimeData): CustomSeriesPricePlotValues {
return [];
}

public isWhitespace(data: NonTimeData | WhitespaceData<HorizontalScaleType>): data is WhitespaceData<HorizontalScaleType> {
return (data as Partial<NonTimeData>).priceY === undefined;
}

public renderer(): ICustomSeriesPaneRenderer {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {} as ICustomSeriesPaneRenderer;
}

public update(
data: PaneRendererCustomData<HorizontalScaleType, NonTimeData>,
options: NonTimeSeriesOptions
): void {}

public defaultOptions(): NonTimeSeriesOptions {
return defaultOptions;
}
}

// @ts-expect-error Mock Class
class MyHorizontalScaleBehaviour implements IHorzScaleBehavior<HorizontalScaleType> {
public isMock(): boolean {
return true;
}
}
const horizontalScaleBehaviourMock = new MyHorizontalScaleBehaviour();

// @ts-expect-error Mock Class
const chart = createChartEx<HorizontalScaleType, MyHorizontalScaleBehaviour>('anything', horizontalScaleBehaviourMock);
const customSeriesView = (new NonTimeSeries()) as ICustomSeriesPaneView<HorizontalScaleType, NonTimeData, NonTimeSeriesOptions>;

// @ts-expect-error invalid property
const failSeries = chart.addCustomSeries(customSeriesView, { badOption: 123 });
// @ts-expect-error invalid value
const failSeries2 = chart.addCustomSeries(customSeriesView, { testOption: 123 });

const series = chart.addCustomSeries(customSeriesView, { testOption: 'string' });

const data: (NonTimeData | WhitespaceData<HorizontalScaleType>)[] = [
{ time: 12345 }, // whitespace
// @ts-expect-error invalid data
{ time: 12345, value: 1234 },
{ time: 12345, priceY: 12345 },
];

series.setData(data);

series.update({ time: 12345 });
// @ts-expect-error invalid data
series.update({ time: 12345, value: 1234 });
series.update({ time: 12345, priceY: 12345 });

const notGreatData: CandlestickData[] = [{ time: 12345 as Time, open: 1234, high: 1234, low: 1234, close: 1234 }];
// @ts-expect-error time is not compatible anymore, type Time isn't always a number
series.setData(notGreatData);

const badData = [{ open: 1234, high: 1234, low: 1234, close: 1234 }] as const;
// @ts-expect-error data should have at least `time` property
series.setData(badData);

const options: Readonly<NonTimeSeriesOptions> = series.options();
// @ts-expect-error not a valid option
options.baseLineColor = 'orange';

// @ts-expect-error invalid property
series.applyOptions({ badOption: 123 });
// @ts-expect-error invalid value
series.applyOptions({ testOption: 123 });
series.applyOptions({ testOption: 'string' });

type ExpectedDataType = NonTimeData | WhitespaceData<HorizontalScaleType>;
export const dataPoint: ExpectedDataType | null = series.dataByIndex(1);

const dataSet: readonly ExpectedDataType[] = series.data();
if (dataSet) {
// @ts-expect-error readonly array
dataSet[0] = { time: 12 };
}
// @ts-expect-error readonly array
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
dataSet.push({ time: 12 });

0 comments on commit 8255ab4

Please sign in to comment.