From 2c4531d1d6dd698ba9134dd23020d5dfc4134015 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Sat, 29 Aug 2026 01:38:37 +0400 Subject: [PATCH 1/4] refactor(dataSourceAdapter): replace dynamic member-copy with explicit delegates --- .../m_data_source_adapter.ts | 75 +++++++++++++++---- .../virtual_scrolling/m_virtual_scrolling.ts | 2 +- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts index c4f74d63da44..c151c4d3a28e 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts @@ -8,9 +8,9 @@ import type { DeferredObj } from '@js/core/utils/deferred'; import { Deferred, when } from '@js/core/utils/deferred'; import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; -import { isDefined, isFunction, isPlainObject } from '@js/core/utils/type'; +import { isDefined, isPlainObject } from '@js/core/utils/type'; import type { StoreChange } from '@js/data/store'; -import type { ChangingEvent, DataSource } from '@ts/data/data_source/types'; +import type { ChangingEvent, DataSource, StoreLoadOptions } from '@ts/data/data_source/types'; import type { BeforePushEvent } from '@ts/data/types'; import modules from '../m_modules'; @@ -99,9 +99,67 @@ export default class DataSourceAdapter extends modules.Controller { private changingHandlerProxy!: (e: ChangingEvent) => void; - protected store!: () => any; + public filter(): StoreLoadOptions['filter']; + public filter(...filterExpr: NonNullable[]): void; + public filter(...args: unknown[]): unknown { + return (this._dataSource.filter as (...a: unknown[]) => unknown)(...args); + } + + public sort(): StoreLoadOptions['sort']; + public sort(...sortExpr: NonNullable[]): void; + public sort(...args: unknown[]): unknown { + return (this._dataSource.sort as (...a: unknown[]) => unknown)(...args); + } - private readonly group!: (args?: any) => any; + public group(): StoreLoadOptions['group']; + public group(...groupExpr: NonNullable[]): void; + public group(...args: unknown[]): unknown { + return (this._dataSource.group as (...a: unknown[]) => unknown)(...args); + } + + public select(): StoreLoadOptions['select']; + public select(...selectExpr: NonNullable[]): void; + public select(...args: unknown[]): unknown { + return (this._dataSource.select as (...a: unknown[]) => unknown)(...args); + } + + public paginate(): boolean | undefined; + public paginate(value: boolean): void; + public paginate(value?: boolean): boolean | undefined { + return (this._dataSource.paginate as (...a: unknown[]) => boolean | undefined)(value); + } + + public requireTotalCount(): StoreLoadOptions['requireTotalCount']; + public requireTotalCount(value: boolean): void; + public requireTotalCount(value?: boolean): unknown { + return (this._dataSource.requireTotalCount as (...a: unknown[]) => unknown)(value); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public store(): any { + return this._dataSource.store(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public key(): any { + return this._dataSource.key(); + } + + public isLoading(): boolean { + return this._dataSource.isLoading(); + } + + public loadOptions(): StoreLoadOptions { + return this._dataSource.loadOptions(); + } + + public cancel(operationId: number): boolean { + return this._dataSource.cancel(operationId); + } + + public cancelAll(): void { + (this._dataSource as unknown as { cancelAll: () => void }).cancelAll(); + } public init(dataSource?: DataSource): void { if (!dataSource) { @@ -147,15 +205,6 @@ export default class DataSourceAdapter extends modules.Controller { dataSource.on('loadError', that.loadErrorHandlerProxy); dataSource.on('changing', that.changingHandlerProxy); dataSource.store().on('beforePush', that.pushHandlerProxy); - - // TODO: remove copying dataSource's members - each(dataSource, (memberName, member) => { - if (!that[memberName] && isFunction(member)) { - that[memberName] = function () { - return this._dataSource[memberName].apply(this._dataSource, arguments); - }; - } - }); } public dispose(isSharedDataSource?: boolean): void { diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts index 8b5f1d40d218..4fa72ae70626 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts @@ -238,7 +238,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return this._virtualScrollController.load(); } - private isLoading() { + public isLoading() { return this.option(LEGACY_SCROLLING_MODE) === false ? this._dataSource.isLoading() : this._isLoading; } From 57d2a991da350c3af5a4cc9c3ba56d5d4fc6856e Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Sat, 29 Aug 2026 16:49:31 +0400 Subject: [PATCH 2/4] refactor(dataController): type _dataSource as DataSourceAdapter --- .../grids/data_grid/export/m_export.ts | 2 +- .../grids/data_grid/focus/m_focus.ts | 2 +- .../grids/data_grid/grouping/m_grouping.ts | 16 +++---- .../extenders/summary_data_controller.ts | 6 ++- .../data_controller/data_controller.ts | 43 ++++++++++-------- .../m_data_source_adapter.ts | 45 ++++++++++--------- .../grids/grid_core/focus/m_focus.ts | 18 ++++---- .../virtual_scrolling_data_controller.ts | 33 ++++++++------ .../virtual_scrolling/m_virtual_scrolling.ts | 43 +++++++++--------- .../data_controller/m_data_controller.ts | 9 ++-- .../m_data_source_adapter.ts | 25 ++++++----- .../js/__internal/grids/tree_list/m_focus.ts | 15 ++++--- .../grids/tree_list/m_virtual_scrolling.ts | 4 +- 13 files changed, 140 insertions(+), 121 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts b/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts index 3cbdec732579..4a8226c4538c 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts @@ -701,7 +701,7 @@ export class ExportController extends dataGridCore.ViewController { private needLoadItemsOnExportingSelectedItems(): boolean { return this.option('loadItemsOnExportingSelectedItems') - ?? this._dataController._dataSource.remoteOperations().filtering; + ?? (this._dataController._dataSource?.remoteOperations().filtering ?? false); } } diff --git a/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts b/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts index 95ad327d2018..007e7464a7bd 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts @@ -88,7 +88,7 @@ const data = (Base: DataControllerBase) => class FocusDataControllerExtender ext } private _calculateGlobalRowIndexByGroupedData(key) { - const dataSource = this._dataSource; + const dataSource = this._dataSource as any; const filter = this._generateFilterByKey(key); // @ts-expect-error const deferred = new Deferred(); diff --git a/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts index 60510ea45ca7..efc6f57f8b35 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts @@ -67,13 +67,13 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class } } - protected totalItemsCount() { + public totalItemsCount() { const totalCount = super.totalItemsCount(); return totalCount > 0 && this._dataSource.group() && this._dataSource.requireTotalCount() ? totalCount + this._grouping.totalCountCorrection() : totalCount; } - protected itemsCount() { + public itemsCount() { return this._dataSource.group() ? this._grouping.itemsCount() || 0 : super.itemsCount.apply(this, arguments as any); } @@ -130,7 +130,7 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class return this._grouping.refresh.apply(this._grouping, arguments); } - protected changeRowExpand(path) { + public changeRowExpand(path) { const that = this; const dataSource = that._dataSource; @@ -192,7 +192,7 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class return this._grouping.handleDataLoading(options); } - protected customizeLoadResultHandler(options) { + public customizeLoadResultHandler(options) { return this._grouping.handleDataLoaded(options, super.customizeLoadResultHandler.bind(this)); } @@ -330,7 +330,7 @@ const GroupingDataControllerExtender = (Base: ModuleType) => cla } private collapseAll(groupIndex) { - const dataSource = this._dataSource; + const dataSource = this._dataSource as any; if (dataSource && dataSource.collapseAll(groupIndex)) { dataSource.pageIndex(0); dataSource.reload(); @@ -338,7 +338,7 @@ const GroupingDataControllerExtender = (Base: ModuleType) => cla } private expandAll(groupIndex) { - const dataSource = this._dataSource; + const dataSource = this._dataSource as any; if (dataSource && dataSource.expandAll(groupIndex)) { dataSource.pageIndex(0); dataSource.reload(); @@ -368,7 +368,7 @@ const GroupingDataControllerExtender = (Base: ModuleType) => cla protected _changeRowExpandCore(key) { const that = this; - const dataSource = this._dataSource; + const dataSource = this._dataSource as any; // @ts-expect-error const d = new Deferred(); @@ -383,7 +383,7 @@ const GroupingDataControllerExtender = (Base: ModuleType) => cla } private isRowExpanded(key) { - const dataSource = this._dataSource; + const dataSource = this._dataSource as any; return dataSource && dataSource.isRowExpanded(key); } diff --git a/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts b/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts index b643c5839210..fc97ff58f1b5 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts @@ -43,7 +43,8 @@ export const summaryDataControllerExtender = ( public getTotalSummaryValue(summaryItemName?: string | number | null): unknown { const summaryItemIndex = getSummaryItemIndex(this.option('summary.totalItems'), summaryItemName); - const aggregates = this._dataSource.totalAggregates(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const aggregates = (this._dataSource as any).totalAggregates(); if (aggregates.length && summaryItemIndex > -1) { return aggregates[summaryItemIndex]; @@ -293,7 +294,8 @@ export const summaryDataControllerExtender = ( this._footerItems = []; if (dataSource && summaryTotalItems?.length) { - const totalAggregates = dataSource.totalAggregates(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const totalAggregates = (dataSource as any).totalAggregates(); const summaryCells = this._getSummaryCells(summaryTotalItems, totalAggregates); if (change?.repaintChangesOnly && oldSummaryCells) { diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts index f94cf949febb..c647edc7332c 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts @@ -66,8 +66,7 @@ import { import { generateRowValues } from './utils/row_values'; export class DataController extends modules.Controller { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _dataSource?: any; + public _dataSource?: DataSourceAdapter; protected isSharedDataSource?: boolean; @@ -188,7 +187,8 @@ export class DataController extends modules.Controller { * @extended: virtual_scrolling */ protected _getPagingOptionValue(optionName: PagingOptionName): number { - return this._dataSource[optionName]() as number; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this._dataSource![optionName]() as number; } protected callbackNames(): string[] { @@ -333,7 +333,7 @@ export class DataController extends modules.Controller { } public getDataSource(): DataSource | null | undefined { - const adapter: DataSourceAdapterLike | null | undefined = this._dataSource; + const adapter = this._dataSource as unknown as DataSourceAdapterLike | null | undefined; return adapter ? adapter._dataSource : null; } @@ -418,6 +418,9 @@ export class DataController extends modules.Controller { private readonly customizeStoreLoadOptionsHandler = (e: LoadOperation): void => { const columnsController = this._columnsController; const dataSource = this._dataSource; + if (!dataSource) { + return; + } const { storeLoadOptions } = e; if (e.isCustomLoading && !storeLoadOptions.isLoadingAll) { @@ -590,7 +593,7 @@ export class DataController extends modules.Controller { errors.log('W1005', this.component.NAME); this._applyFilter(); } else { - this._currentOperationTypes = dataSource.operationTypes(); + this._currentOperationTypes = dataSource.operationTypes() ?? null; const change: DataChange = isDefined(e) ? { @@ -726,7 +729,7 @@ export class DataController extends modules.Controller { dataSource.load().done((...args: unknown[]) => { this._isPaging = false; result.resolve(...args); - }).fail(result.reject); + }).fail(result.reject as (...args: unknown[]) => void); } else { result.resolve(); } @@ -1450,7 +1453,7 @@ export class DataController extends modules.Controller { ? this._createDataSourceAdapter(dataSource) : null; - this._dataSource = dataSourceAdapter; + this._dataSource = dataSourceAdapter ?? undefined; if (dataSourceAdapter) { this._isLoading = !dataSourceAdapter.isLoaded(); @@ -1478,7 +1481,7 @@ export class DataController extends modules.Controller { } public pageCount(): number { - return this._dataSource ? this._dataSource.pageCount() as number : 1; + return this._dataSource ? this._dataSource.pageCount() : 1; } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -1525,15 +1528,15 @@ export class DataController extends modules.Controller { requireTotalCount: false, }; dataSource.load(loadOptions) - .done((loadedItems: RawItemData[], extra: LoadOperation['extra']): void => { + .done((loadedItems: unknown, extra: unknown): void => { const items = this._processItems( - this._beforeProcessItems(loadedItems), + this._beforeProcessItems(loadedItems as RawItemData[]), { changeType: 'loadingAll' }, ); // @ts-expect-error DataGrid-only summary leaks into grid_core - d.resolve(items, extra?.summary); + d.resolve(items, (extra as LoadOperation['extra'])?.summary); }) - .fail(d.reject); + .fail(d.reject as (...args: unknown[]) => void); } else { d.reject(); } @@ -1628,10 +1631,12 @@ export class DataController extends modules.Controller { this._skipProcessingPagingChange = false; } - const pageIndex = dataSource.pageIndex(); + const pageIndex = dataSource.pageIndex() as unknown as number; this._isPaging = optionName === 'pageIndex'; - const loadResult: DeferredObj = dataSource[optionName === 'pageIndex' ? 'load' : 'reload'](); + const loadResult: DeferredObj = ( + dataSource[optionName === 'pageIndex' ? 'load' : 'reload'] as () => DeferredObj + )(); return loadResult.done(() => { this._isPaging = false; @@ -1779,19 +1784,19 @@ export class DataController extends modules.Controller { } public push(...args: unknown[]): unknown { - return this._dataSource?.push(...args); + return (this._dataSource?.push as ((...a: unknown[]) => unknown) | undefined)?.(...args); } private itemsCount(): number { - return (this._dataSource ? this._dataSource.itemsCount() : 0) as number; + return (this._dataSource ? this._dataSource.itemsCount() : 0); } public totalItemsCount(): number { - return (this._dataSource ? this._dataSource.totalItemsCount() : 0) as number; + return (this._dataSource ? this._dataSource.totalItemsCount() : 0); } public hasKnownLastPage(): boolean { - return (this._dataSource ? this._dataSource.hasKnownLastPage() : true) as boolean; + return (this._dataSource ? this._dataSource.hasKnownLastPage() : true); } /** @@ -1802,7 +1807,7 @@ export class DataController extends modules.Controller { } public totalCount(): number { - return (this._dataSource ? this._dataSource.totalCount() : 0) as number; + return (this._dataSource ? this._dataSource.totalCount() : 0); } public hasLoadOperation(): boolean { diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts index c151c4d3a28e..5f6dfabc9b90 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts @@ -100,25 +100,25 @@ export default class DataSourceAdapter extends modules.Controller { private changingHandlerProxy!: (e: ChangingEvent) => void; public filter(): StoreLoadOptions['filter']; - public filter(...filterExpr: NonNullable[]): void; + public filter(filterExpr: StoreLoadOptions['filter']): void; public filter(...args: unknown[]): unknown { return (this._dataSource.filter as (...a: unknown[]) => unknown)(...args); } public sort(): StoreLoadOptions['sort']; - public sort(...sortExpr: NonNullable[]): void; + public sort(sortExpr: StoreLoadOptions['sort']): void; public sort(...args: unknown[]): unknown { return (this._dataSource.sort as (...a: unknown[]) => unknown)(...args); } public group(): StoreLoadOptions['group']; - public group(...groupExpr: NonNullable[]): void; + public group(groupExpr: StoreLoadOptions['group']): void; public group(...args: unknown[]): unknown { return (this._dataSource.group as (...a: unknown[]) => unknown)(...args); } public select(): StoreLoadOptions['select']; - public select(...selectExpr: NonNullable[]): void; + public select(selectExpr: StoreLoadOptions['select']): void; public select(...args: unknown[]): unknown { return (this._dataSource.select as (...a: unknown[]) => unknown)(...args); } @@ -245,7 +245,7 @@ export default class DataSourceAdapter extends modules.Controller { } } - private resetCurrentTotalCount() { + public resetCurrentTotalCount() { this._currentTotalCount = 0; this._totalCountCorrection = 0; } @@ -276,7 +276,7 @@ export default class DataSourceAdapter extends modules.Controller { return !isLocalOperations; } - private push(changes: StoreChange[], fromStore: boolean): void { + public push(changes: StoreChange[], fromStore: boolean): void { const store = this.store(); if (this._needClearStoreDataCache()) { @@ -305,7 +305,7 @@ export default class DataSourceAdapter extends modules.Controller { this.pushed.fire(changes); } - private getDataIndexGetter() { + public getDataIndexGetter() { if (!this._dataIndexGetter) { const store = this.store(); @@ -565,7 +565,7 @@ export default class DataSourceAdapter extends modules.Controller { /** * @extended: TreeLists's data_source_adapter */ - protected customizeLoadResultHandler(options) { + public customizeLoadResultHandler(options) { const { loadOptions } = options; const localPaging = options.remoteOperations && !options.remoteOperations.paging; const { cachedData } = options; @@ -774,7 +774,7 @@ export default class DataSourceAdapter extends modules.Controller { return this._operationTypes; } - private lastLoadOptions() { + public lastLoadOptions() { return this._lastLoadOptions || {}; } @@ -799,14 +799,14 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: TreeLists's data_source_adapter */ // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected changeRowExpand(path?: any): any {} + public changeRowExpand(path?: any): any {} - private totalCount() { + public totalCount() { // eslint-disable-next-line radix return parseInt((this._currentTotalCount || this._dataSourceTotalCount()) + this._totalCountCorrection); } - private totalCountCorrection() { + public totalCountCorrection() { return this._totalCountCorrection; } @@ -814,19 +814,19 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling * @protected */ - protected items(): any {} + public items(): any {} /** * @extended: virtual_scrolling */ - protected itemsCount() { + public itemsCount() { return this._dataSource.items().length; } /** * @extended: TreeLists's data_source_adapter */ - protected totalItemsCount() { + public totalItemsCount() { return this.totalCount(); } @@ -841,7 +841,7 @@ export default class DataSourceAdapter extends modules.Controller { return this._dataSource.pageSize(value); } - protected pageCount() { + public pageCount() { const that = this; const count = that.totalItemsCount() - that._totalCountCorrection; const pageSize = that.pageSize(); @@ -852,7 +852,7 @@ export default class DataSourceAdapter extends modules.Controller { return 1; } - protected hasKnownLastPage() { + public hasKnownLastPage() { return this._hasLastPage || this._dataSource.totalCount() >= 0; } @@ -876,14 +876,14 @@ export default class DataSourceAdapter extends modules.Controller { return d; } - protected isCustomLoading() { + public isCustomLoading() { return !!this._isCustomLoading; } /** * @extended: virtual_scrolling */ - protected load(options?): DeferredObj { + public load(options?): DeferredObj { const that = this; const dataSource = that._dataSource; const d = Deferred(); @@ -943,12 +943,13 @@ export default class DataSourceAdapter extends modules.Controller { /** * @extended: virtual_scrolling */ - protected reload(full: boolean): DeferredObj { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public reload(full?: boolean, changesOnly?: boolean): DeferredObj { const result = full ? this._dataSource.reload() : this._dataSource.load(); return result as unknown as DeferredObj; } - private getCachedStoreData() { + public getCachedStoreData() { return this._cachedStoreData; } @@ -961,5 +962,5 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling */ // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected pageIndex(pageIndex?) {} + public pageIndex(pageIndex?) {} } diff --git a/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts b/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts index 39fb37dd160b..e24d0d55a716 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts @@ -546,7 +546,7 @@ const columns = (Base: ModuleType) => class FocusColumnsExten if (notSortedKeys.length) { result = result || []; if (isLocalOperations) { - result.push({ selector: dataSource.getDataIndexGetter(), desc: false }); + result.push({ selector: dataSource!.getDataIndexGetter(), desc: false }); } else { notSortedKeys.forEach((notSortedKey) => result.push({ selector: notSortedKey, desc: false })); } @@ -708,7 +708,7 @@ const focusDataControllerExtender = ( } private getGlobalRowIndexByKey(key) { - if (this._dataSource.group()) { + if (this._dataSource!.group()) { // @ts-expect-error return this._calculateGlobalRowIndexByGroupedData(key); } @@ -719,7 +719,7 @@ const focusDataControllerExtender = ( protected _calculateGlobalRowIndexByFlatData(key, groupFilter, useGroup) { // @ts-expect-error const deferred = new Deferred(); - const dataSource = this._dataSource; + const dataSource = this._dataSource!; if (Array.isArray(key) || isNewRowTempKey(key)) { return deferred.resolve(-1).promise(); @@ -736,8 +736,8 @@ const focusDataControllerExtender = ( deferred.resolve(-1); return; } - if (data.length > 0) { - filter = this._generateOperationFilterByKey(key, data[0], useGroup); + if ((data as unknown[]).length > 0) { + filter = this._generateOperationFilterByKey(key, (data as unknown[])[0], useGroup); dataSource.load({ filter: this._concatWithCombinedFilter(filter, groupFilter), skip: 0, @@ -748,7 +748,7 @@ const focusDataControllerExtender = ( deferred.resolve(-1); return; } - deferred.resolve(extra.totalCount); + deferred.resolve((extra as { totalCount: number }).totalCount); }); } else { deferred.resolve(-1); @@ -784,8 +784,8 @@ const focusDataControllerExtender = ( private _generateOperationFilterByKey(key, rowData, useGroup) { const that = this; const dateSerializationFormat = that.option('dateSerializationFormat'); - const isRemoteFiltering = that._dataSource.remoteOperations().filtering; - const isRemoteSorting = that._dataSource.remoteOperations().sorting; + const isRemoteFiltering = that._dataSource!.remoteOperations().filtering; + const isRemoteSorting = that._dataSource!.remoteOperations().sorting; let filter = that._generateFilterByKey(key, '<'); // @ts-expect-error @@ -846,7 +846,7 @@ const focusDataControllerExtender = ( } protected _generateFilterByKey(key, operation?) { - const dataSourceKey = this._dataSource.key(); + const dataSourceKey = this._dataSource!.key(); let filter: any = []; if (!operation) { diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts index 8903563cd5e9..7082e7da56fa 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts @@ -34,6 +34,7 @@ import { LOAD_TIMEOUT, VISIBLE_PAGE_INDEX, } from '../const'; +import type { dataSourceAdapterExtender } from '../m_virtual_scrolling'; import { VirtualScrollController } from '../m_virtual_scrolling_core'; import type { ChangedLoadParams } from '../types'; import { @@ -51,11 +52,15 @@ export interface VirtualScrollingDataControllerExtension { virtualItemsCount: () => VirtualItemsCount | undefined; } +type VirtualScrollingDataSourceAdapter = InstanceType>; + export const virtualScrollingDataControllerExtender = ( Base: ModuleType, ): ModuleType< DataController & VirtualScrollingDataControllerExtension > => class VirtualScrollingDataControllerExtender extends Base { + public declare _dataSource?: VirtualScrollingDataSourceAdapter; + private _loadViewportParams: any; private _allItems: any; @@ -106,7 +111,7 @@ export const virtualScrollingDataControllerExtender = ( // eslint-disable-next-line @typescript-eslint/no-unused-vars public reload(reload?: boolean, changesOnly?: boolean): DeferredObj { const rowsScrollController = this._rowsScrollController || this._dataSource; - const itemIndex = rowsScrollController?.getItemIndexByPosition(); + const itemIndex = (rowsScrollController as any)?.getItemIndexByPosition(); const result = super.reload.apply(this, arguments as any); return result?.done(() => { if (isVirtualMode(this) || gridCoreUtils.isVirtualRowRendering(this)) { @@ -175,7 +180,7 @@ export const virtualScrollingDataControllerExtender = ( private _getRowsScrollDataOptions() { const that = this; const isItemCountable = function (item) { - return isItemCountableByDataSource(item, that._dataSource); + return isItemCountableByDataSource(item, that._dataSource as any); }; return { @@ -369,7 +374,7 @@ export const virtualScrollingDataControllerExtender = ( processedItems.forEach((item) => { const { rowType } = item; - const itemCountable = isItemCountableByDataSource(item, dataSource); + const itemCountable = isItemCountableByDataSource(item, dataSource as any); const isNextGroupItem = rowType === 'group' && (prevCountable || (prevRowType !== 'group' && currentIndex > 0)); const isNextDataItem = rowType === 'data' && itemCountable && (prevCountable || prevRowType !== 'group'); @@ -403,7 +408,7 @@ export const virtualScrollingDataControllerExtender = ( } protected _afterProcessItems(processedItems: ProcessedItem[]): ProcessedItem[] { - this._itemCount = processedItems.filter((item) => isItemCountableByDataSource(item, this._dataSource)).length; + this._itemCount = processedItems.filter((item) => isItemCountableByDataSource(item, this._dataSource as any)).length; if (isDefined(this._loadViewportParams)) { this._updateLoadViewportParams(); @@ -438,7 +443,7 @@ export const virtualScrollingDataControllerExtender = ( if (removeCount) { const fromEnd = changeType === 'prepend'; - removeCount = correctCount(that._items, removeCount, fromEnd, (item, isNextAfterLast) => isItemCountableByDataSource(item, that._dataSource) || (item.rowType === 'group' && isNextAfterLast)); + removeCount = correctCount(that._items, removeCount, fromEnd, (item, isNextAfterLast) => isItemCountableByDataSource(item, that._dataSource as any) || (item.rowType === 'group' && isNextAfterLast)); change.removeCount = removeCount; } @@ -537,7 +542,7 @@ export const virtualScrollingDataControllerExtender = ( return result; } - return dataSource?.viewportSize.apply(dataSource, arguments); + return dataSource?.viewportSize.apply(dataSource, arguments as unknown as []); } private viewportHeight(height, scrollTop) { @@ -554,7 +559,7 @@ export const virtualScrollingDataControllerExtender = ( return result; } - return dataSource?.viewportItemSize.apply(dataSource, arguments); + return dataSource?.viewportItemSize.apply(dataSource, arguments as unknown as []); } private setViewportPosition() { @@ -566,7 +571,7 @@ export const virtualScrollingDataControllerExtender = ( // @ts-expect-error rowsScrollController.setViewportPosition.apply(rowsScrollController, arguments); } else { - dataSource?.setViewportPosition.apply(dataSource, arguments); + dataSource?.setViewportPosition.apply(dataSource, arguments as unknown as []); } } @@ -738,8 +743,8 @@ export const virtualScrollingDataControllerExtender = ( } private loadPages(changedParams: ChangedLoadParams): void { - this._dataSource.pageIndex(changedParams.pageIndex); - this._dataSource.loadPageCount(changedParams.loadPageCount); + this._dataSource!.pageIndex(changedParams.pageIndex); + this._dataSource!.loadPageCount(changedParams.loadPageCount); this._repaintChangesOnly = true; this._needUpdateDimensions = true; @@ -831,7 +836,7 @@ export const virtualScrollingDataControllerExtender = ( } const dataSource = this._dataSource; - return dataSource?.getItemSize.apply(dataSource, arguments); + return dataSource?.getItemSize.apply(dataSource, arguments as unknown as []); } private getItemSizes() { @@ -843,7 +848,7 @@ export const virtualScrollingDataControllerExtender = ( } const dataSource = this._dataSource; - return dataSource?.getItemSizes.apply(dataSource, arguments); + return dataSource?.getItemSizes.apply(dataSource, arguments as unknown as []); } private getContentOffset() { @@ -855,7 +860,7 @@ export const virtualScrollingDataControllerExtender = ( } const dataSource = this._dataSource; - return dataSource?.getContentOffset.apply(dataSource, arguments); + return dataSource?.getContentOffset.apply(dataSource, arguments as unknown as []); } public refresh(options?: boolean | RefreshOptions): DeferredObj { @@ -908,7 +913,7 @@ export const virtualScrollingDataControllerExtender = ( const { fullReload, pageIndex } = operationTypes; if (e.isDataChanged && !fullReload && pageIndex) { - this._updateVisiblePageIndex(this._dataSource.pageIndex()); + this._updateVisiblePageIndex(this._dataSource!.pageIndex()); } } } diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts index 4fa72ae70626..9822b9fc6f6c 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts @@ -216,7 +216,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = super._customizeRemoteOperations.apply(this, arguments as any); } - protected items() { + public items() { return this._items; } @@ -224,14 +224,14 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return this.option(LEGACY_SCROLLING_MODE) === false && isVirtualMode(this) && !isBase ? this._totalCount : super._dataSourceTotalCount(); } - protected itemsCount(isBase?) { + public itemsCount(isBase?) { if (isBase || this.option(LEGACY_SCROLLING_MODE) === false) { return super.itemsCount(); } return this._virtualScrollController.itemsCount(); } - protected load(loadOptions) { + public load(loadOptions) { if (this.option(LEGACY_SCROLLING_MODE) === false || loadOptions) { return super.load(loadOptions); } @@ -266,7 +266,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return result; } - protected reload() { + public reload() { this._dataSource.pageIndex(this.pageIndex()); const virtualScrollController = this._virtualScrollController; @@ -320,7 +320,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return super.refresh.apply(this, arguments as any); } - private loadPageCount(count?) { + public loadPageCount(count?) { if (!isDefined(count)) { return this._loadPageCount; } @@ -354,27 +354,28 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = } // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected pageIndex(pageIndex?): any { + public pageIndex(pageIndex?): any { return proxyDataSourceAdapterMethod(this, 'pageIndex', [...arguments]); } - private virtualItemsCount(): any { + public virtualItemsCount(): any { return proxyDataSourceAdapterMethod(this, 'virtualItemsCount', [...arguments]); } - private getContentOffset(): any { + public getContentOffset(): any { return proxyDataSourceAdapterMethod(this, 'getContentOffset', [...arguments]); } - private getVirtualContentSize(): any { + public getVirtualContentSize(): any { return proxyDataSourceAdapterMethod(this, 'getVirtualContentSize', [...arguments]); } - private setContentItemSizes(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public setContentItemSizes(sizes?): any { return proxyDataSourceAdapterMethod(this, 'setContentItemSizes', [...arguments]); } - private setViewportPosition(): any { + public setViewportPosition(): any { return proxyDataSourceAdapterMethod(this, 'setViewportPosition', [...arguments]); } @@ -387,27 +388,27 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return proxyDataSourceAdapterMethod(this, 'setViewportItemIndex', [...arguments]); } - private getItemIndexByPosition(): any { + public getItemIndexByPosition(): any { return proxyDataSourceAdapterMethod(this, 'getItemIndexByPosition', [...arguments]); } - private viewportSize(): any { + public viewportSize(): any { return proxyDataSourceAdapterMethod(this, 'viewportSize', [...arguments]); } - private viewportItemSize(): any { + public viewportItemSize(): any { return proxyDataSourceAdapterMethod(this, 'viewportItemSize', [...arguments]); } - private getItemSize(): any { + public getItemSize(): any { return proxyDataSourceAdapterMethod(this, 'getItemSize', [...arguments]); } - private getItemSizes(): any { + public getItemSizes(): any { return proxyDataSourceAdapterMethod(this, 'getItemSizes', [...arguments]); } - private loadIfNeed(): any { + public loadIfNeed(): any { return proxyDataSourceAdapterMethod(this, 'loadIfNeed', [...arguments]); } }; @@ -582,9 +583,9 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo .viewportSize() || 20; if (gridCoreUtils.isVirtualRowRendering(this) && itemCount > 0 && this.option(LEGACY_SCROLLING_MODE) !== false) { - dataSource._renderTime = ((new Date()) as any - startRenderTime) * viewportSize / itemCount; + (dataSource as any)._renderTime = ((new Date()) as any - startRenderTime) * viewportSize / itemCount; } else { - dataSource._renderTime = ((new Date()) as any - startRenderTime); + (dataSource as any)._renderTime = ((new Date()) as any - startRenderTime); } } return deferred; @@ -718,7 +719,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo itemSize = 0; } lastLoadIndex = currentItem.loadIndex; - } else if (isItemCountableByDataSource(currentItem, dataSource)) { + } else if (isItemCountableByDataSource(currentItem, dataSource as any)) { if (firstCountableItem) { firstCountableItem = false; } else { @@ -964,7 +965,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo } } - private loadIfNeed() { + public loadIfNeed() { this._dataController // @ts-expect-error ?.loadIfNeed?.(); diff --git a/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts b/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts index f0fa6c4d443e..ad488a18d056 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts @@ -5,10 +5,13 @@ import { DataController, dataControllerModule } from '@ts/grids/grid_core/data_c import type { DataSourceAdapterProvider } from '@ts/grids/grid_core/data_source_adapter/types'; import type { RowKey } from '@ts/grids/grid_core/m_types'; +import type { DataSourceAdapterTreeList } from '../data_source_adapter/m_data_source_adapter'; import dataSourceAdapterProvider from '../data_source_adapter/m_data_source_adapter'; import treeListCore from '../m_core'; export class TreeListDataController extends DataController { + public declare _dataSource?: DataSourceAdapterTreeList; + protected _getDataSourceAdapterProvider(): DataSourceAdapterProvider { return dataSourceAdapterProvider; } @@ -36,7 +39,7 @@ export class TreeListDataController extends DataController { } private _loadOnOptionChange() { - this._dataSource.load(); + this._dataSource!.load(); } protected isSameRowState(item1, item2): boolean { @@ -163,7 +166,7 @@ export class TreeListDataController extends DataController { break; case 'expandedRowKeys': case 'onNodesInitialized': - if (this._dataSource && !this._dataSource._isNodesInitializing && !equalByValue(args.value, args.previousValue)) { + if (this._dataSource && !(this._dataSource as any)._isNodesInitializing && !equalByValue(args.value, args.previousValue)) { this._loadOnOptionChange(); } args.handled = true; @@ -201,7 +204,7 @@ export class TreeListDataController extends DataController { } private forEachNode() { - this._dataSource.forEachNode.apply(this, arguments); + this._dataSource!.forEachNode.apply(this, arguments as unknown as []); } // Collect keys by walking the loaded node tree (depth-first, parent before diff --git a/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts b/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts index 476cf246decf..39040cc50977 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts @@ -615,7 +615,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return baseChanges; } - protected customizeLoadResultHandler(options) { + public customizeLoadResultHandler(options) { const data = options.data = this._convertDataToPlainStructure(options.data); if (!options.remoteOperations.filtering && options.loadOptions.filter) { // @ts-expect-error @@ -771,7 +771,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { this.createAction('onNodesInitialized'); } - private getKeyExpr() { + public getKeyExpr() { const store = this.store(); const key = store && store.key(); const keyExpr = this.option('keyExpr'); @@ -785,23 +785,23 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return key || keyExpr || DEFAULT_KEY_EXPRESSION; } - private keyOf(data) { + public keyOf(data) { return this._keyGetter && this._keyGetter(data); } - private parentKeyOf(data) { + public parentKeyOf(data) { return this._parentIdGetter && this._parentIdGetter(data); } - private getRootNode() { + public getRootNode() { return this._rootNode; } - protected totalItemsCount() { + public totalItemsCount() { return this._totalItemsCount + this._totalCountCorrection; } - private isRowExpanded(key, cache?) { + public isRowExpanded(key, cache?) { if (cache) { let { isExpandedByKey } = cache; if (!isExpandedByKey) { @@ -834,13 +834,13 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { this.option('expandedRowKeys', expandedRowKeys); } - protected changeRowExpand(key) { + public changeRowExpand(key) { this._changeRowExpandCore(key); // @ts-expect-error return this._isNodesInitializing ? new Deferred().resolve() : this.load(); } - private getNodeByKey(key) { + public getNodeByKey(key) { if (this._nodeByKey) { return this._nodeByKey[key]; } @@ -862,7 +862,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return result; } - private getChildNodeKeys(parentKey) { + public getChildNodeKeys(parentKey) { const node = this.getNodeByKey(parentKey); const childrenKeys: any[] = []; @@ -873,7 +873,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return childrenKeys; } - private loadDescendants(keys, childrenOnly) { + public loadDescendants(keys, childrenOnly) { const that = this; // @ts-expect-error const d = new Deferred(); @@ -909,7 +909,8 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return d.promise(); } - private forEachNode() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any + public forEachNode(nodeCallback?: (node: any) => void) { let nodes = []; let callback; diff --git a/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts b/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts index f65678a32c3c..523812f655be 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts @@ -3,6 +3,7 @@ import { focusModule } from '@ts/grids/grid_core/focus/m_focus'; import type { DataController } from '../grid_core/data_controller/data_controller'; import type { ModuleType } from '../grid_core/m_types'; +import type { DataSourceAdapterTreeList } from './data_source_adapter/m_data_source_adapter'; import core from './m_core'; function findIndex(items, callback) { @@ -51,7 +52,7 @@ const data = ( private getParentKey(key) { const that = this; - const dataSource = that._dataSource; + const dataSource = that._dataSource as unknown as DataSourceAdapterTreeList; // @ts-expect-error const node = that.getNodeByKey(key); // @ts-expect-error @@ -63,7 +64,7 @@ const data = ( dataSource.load({ filter: [dataSource.getKeyExpr(), '=', key], }).done((items) => { - const parentData = items[0]; + const parentData = (items as unknown[])[0]; if (parentData) { d.resolve(dataSource.parentKeyOf(parentData)); @@ -78,16 +79,16 @@ const data = ( private expandAscendants(key) { const that = this; - const dataSource = that._dataSource; + const dataSource = that._dataSource as unknown as DataSourceAdapterTreeList; // @ts-expect-error const d = new Deferred(); that.getParentKey(key).done((parentKey) => { if (dataSource && parentKey !== undefined && parentKey !== that.option('rootValue')) { - dataSource._isNodesInitializing = true; + (dataSource as any)._isNodesInitializing = true; // @ts-expect-error that.expandRow(parentKey); - dataSource._isNodesInitializing = false; + (dataSource as any)._isNodesInitializing = false; that.expandAscendants(parentKey).done(d.resolve).fail(d.reject); } else { d.resolve(); @@ -98,7 +99,7 @@ const data = ( } protected getPageIndexByKey(key) { - const dataSource = this._dataSource; + const dataSource = this._dataSource as unknown as DataSourceAdapterTreeList; // @ts-expect-error const d = new Deferred(); @@ -106,7 +107,7 @@ const data = ( dataSource.load({ parentIds: [], }).done((nodes) => { - if (this._dataSource !== dataSource) { + if ((this._dataSource as unknown) !== (dataSource as unknown)) { d.resolve(-1); return; } diff --git a/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts b/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts index 087fcd9315ca..a314864dd925 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts @@ -35,7 +35,7 @@ virtualScrollingModule.extenders.views.rowsView = (Base: ModuleType) = virtualScrollingModule.extenders.controllers.data = (Base: ModuleType) => class TreeListVirtualScrollingDataControllerExtender extends virtualScrollingDataControllerExtender(Base) { protected _loadOnOptionChange() { - const virtualScrollController = this._dataSource?._virtualScrollController; + const virtualScrollController = (this._dataSource as any)?._virtualScrollController; virtualScrollController?.reset(); // @ts-expect-error @@ -44,7 +44,7 @@ virtualScrollingModule.extenders.controllers.data = (Base: ModuleType) => class VirtualScrollingDataSourceAdapterExtender extends virtualScrollingDataSourceAdapterExtender(Base) { - protected changeRowExpand() { + public changeRowExpand() { return super.changeRowExpand.apply(this, arguments as any).done(() => { const viewportItemIndex = this.getViewportItemIndex(); From 3ca0c3b7fef6c35bac9c5e49036a823bed9f85e1 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Sat, 29 Aug 2026 21:21:36 +0400 Subject: [PATCH 3/4] fix(dataSourceAdapter): add beginLoading/endLoading delegates missed in de-proxy --- .../data_source_adapter/m_data_source_adapter.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts index 5f6dfabc9b90..d9b1c7578b9f 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts @@ -149,6 +149,14 @@ export default class DataSourceAdapter extends modules.Controller { return this._dataSource.isLoading(); } + public beginLoading(): void { + this._dataSource.beginLoading(); + } + + public endLoading(): void { + this._dataSource.endLoading(); + } + public loadOptions(): StoreLoadOptions { return this._dataSource.loadOptions(); } From 1a292cc811cd29225d1f820b7182d5b715c91b97 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:23:50 +0400 Subject: [PATCH 4/4] fix(dataController): allow null _dataSource + complete MockGridDataSource for unconditional delegates --- .../grid_core/data_controller/data_controller.ts | 4 ++-- .../devextreme/testing/helpers/gridBaseMocks.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts index c647edc7332c..a6f6f23f3de2 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts @@ -66,7 +66,7 @@ import { import { generateRowValues } from './utils/row_values'; export class DataController extends modules.Controller { - public _dataSource?: DataSourceAdapter; + public _dataSource?: DataSourceAdapter | null; protected isSharedDataSource?: boolean; @@ -1453,7 +1453,7 @@ export class DataController extends modules.Controller { ? this._createDataSourceAdapter(dataSource) : null; - this._dataSource = dataSourceAdapter ?? undefined; + this._dataSource = dataSourceAdapter; if (dataSourceAdapter) { this._isLoading = !dataSourceAdapter.isLoaded(); diff --git a/packages/devextreme/testing/helpers/gridBaseMocks.js b/packages/devextreme/testing/helpers/gridBaseMocks.js index 029e59537099..6d95e1664206 100644 --- a/packages/devextreme/testing/helpers/gridBaseMocks.js +++ b/packages/devextreme/testing/helpers/gridBaseMocks.js @@ -808,6 +808,19 @@ module.exports = function($, gridCore, columnResizingReordering, domUtils, commo cancelAll: commonUtils.noop, + loadOptions: function() { + return {}; + }, + beginLoading: commonUtils.noop, + endLoading: commonUtils.noop, + key: function() { + return options.key; + }, + select: function() { + return options.select; + }, + cancel: commonUtils.noop, + on(eventName, eventHandler) { this[eventName].add(eventHandler); },