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 01/14] 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 02/14] 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 03/14] 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 04/14] 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); }, From ae2208c7e06c5017dcf76a8a6afb3d000d7a9b25 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 11:15:57 +0400 Subject: [PATCH 05/14] refactor(dataController): carry null in narrowed _dataSource decls + mock cancel returns boolean --- .../extenders/virtual_scrolling_data_controller.ts | 2 +- .../grids/tree_list/data_controller/m_data_controller.ts | 2 +- packages/devextreme/testing/helpers/gridBaseMocks.js | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) 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 7082e7da56fa..95bc5d9d6bc0 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 @@ -59,7 +59,7 @@ export const virtualScrollingDataControllerExtender = ( ): ModuleType< DataController & VirtualScrollingDataControllerExtension > => class VirtualScrollingDataControllerExtender extends Base { - public declare _dataSource?: VirtualScrollingDataSourceAdapter; + public declare _dataSource?: VirtualScrollingDataSourceAdapter | null; private _loadViewportParams: any; 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 ad488a18d056..587588c1e995 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 @@ -10,7 +10,7 @@ import dataSourceAdapterProvider from '../data_source_adapter/m_data_source_adap import treeListCore from '../m_core'; export class TreeListDataController extends DataController { - public declare _dataSource?: DataSourceAdapterTreeList; + public declare _dataSource?: DataSourceAdapterTreeList | null; protected _getDataSourceAdapterProvider(): DataSourceAdapterProvider { return dataSourceAdapterProvider; diff --git a/packages/devextreme/testing/helpers/gridBaseMocks.js b/packages/devextreme/testing/helpers/gridBaseMocks.js index 6d95e1664206..9f4eb8f29e91 100644 --- a/packages/devextreme/testing/helpers/gridBaseMocks.js +++ b/packages/devextreme/testing/helpers/gridBaseMocks.js @@ -819,7 +819,9 @@ module.exports = function($, gridCore, columnResizingReordering, domUtils, commo select: function() { return options.select; }, - cancel: commonUtils.noop, + cancel: function() { + return false; + }, on(eventName, eventHandler) { this[eventName].add(eventHandler); From 8cde2285139c037931cee827ef61d5a3a2896eb0 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 11:30:15 +0400 Subject: [PATCH 06/14] refactor(dataController): use arguments as any for delegation to match repo pattern --- .../extenders/virtual_scrolling_data_controller.ts | 12 ++++++------ .../tree_list/data_controller/m_data_controller.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) 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 95bc5d9d6bc0..0efa6e09c494 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 @@ -542,7 +542,7 @@ export const virtualScrollingDataControllerExtender = ( return result; } - return dataSource?.viewportSize.apply(dataSource, arguments as unknown as []); + return dataSource?.viewportSize.apply(dataSource, arguments as any); } private viewportHeight(height, scrollTop) { @@ -559,7 +559,7 @@ export const virtualScrollingDataControllerExtender = ( return result; } - return dataSource?.viewportItemSize.apply(dataSource, arguments as unknown as []); + return dataSource?.viewportItemSize.apply(dataSource, arguments as any); } private setViewportPosition() { @@ -571,7 +571,7 @@ export const virtualScrollingDataControllerExtender = ( // @ts-expect-error rowsScrollController.setViewportPosition.apply(rowsScrollController, arguments); } else { - dataSource?.setViewportPosition.apply(dataSource, arguments as unknown as []); + dataSource?.setViewportPosition.apply(dataSource, arguments as any); } } @@ -836,7 +836,7 @@ export const virtualScrollingDataControllerExtender = ( } const dataSource = this._dataSource; - return dataSource?.getItemSize.apply(dataSource, arguments as unknown as []); + return dataSource?.getItemSize.apply(dataSource, arguments as any); } private getItemSizes() { @@ -848,7 +848,7 @@ export const virtualScrollingDataControllerExtender = ( } const dataSource = this._dataSource; - return dataSource?.getItemSizes.apply(dataSource, arguments as unknown as []); + return dataSource?.getItemSizes.apply(dataSource, arguments as any); } private getContentOffset() { @@ -860,7 +860,7 @@ export const virtualScrollingDataControllerExtender = ( } const dataSource = this._dataSource; - return dataSource?.getContentOffset.apply(dataSource, arguments as unknown as []); + return dataSource?.getContentOffset.apply(dataSource, arguments as any); } public refresh(options?: boolean | RefreshOptions): DeferredObj { 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 587588c1e995..ae9a248a14e4 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 @@ -204,7 +204,7 @@ export class TreeListDataController extends DataController { } private forEachNode() { - this._dataSource!.forEachNode.apply(this, arguments as unknown as []); + this._dataSource!.forEachNode.apply(this, arguments as any); } // Collect keys by walking the loaded node tree (depth-first, parent before From d70bd1bcd90f25261d8072a6f452c86fcf3cab91 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:03:12 +0400 Subject: [PATCH 07/14] refactor(dataController): address review - @ts-expect-error over casts, reorder getters, drop dead enumerable shim, remove that=this --- .../data/data_source/data_source.ts | 18 -- .../grids/data_grid/focus/m_focus.ts | 10 +- .../extenders/grouping_data_controller.ts | 23 ++- .../extenders/summary_data_controller.ts | 8 +- .../data_controller/data_controller.ts | 18 +- .../m_data_source_adapter.ts | 171 +++++++++--------- .../grids/grid_core/focus/m_focus.ts | 2 +- 7 files changed, 113 insertions(+), 137 deletions(-) diff --git a/packages/devextreme/js/__internal/data/data_source/data_source.ts b/packages/devextreme/js/__internal/data/data_source/data_source.ts index 79350d094d78..72aae3df3fab 100644 --- a/packages/devextreme/js/__internal/data/data_source/data_source.ts +++ b/packages/devextreme/js/__internal/data/data_source/data_source.ts @@ -788,21 +788,3 @@ export class DataSource { return this; } } - -/* - * `Class.inherit()` defined prototype members as enumerable, and consumers still rely on - * that: the grid's DataSourceAdapter copies a data source's members with a `for…in` loop - * (see its "remove copying dataSource's members" TODO). ES6 class methods are not - * enumerable, so restore the descriptors a data source used to expose. - */ -Object.getOwnPropertyNames(DataSource.prototype).forEach((memberName) => { - if (memberName === 'constructor') { - return; - } - - const descriptor = Object.getOwnPropertyDescriptor(DataSource.prototype, memberName); - - if (descriptor) { - Object.defineProperty(DataSource.prototype, memberName, { ...descriptor, enumerable: true }); - } -}); 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 007e7464a7bd..3aa4315f72de 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,17 +88,19 @@ const data = (Base: DataControllerBase) => class FocusDataControllerExtender ext } private _calculateGlobalRowIndexByGroupedData(key) { - const dataSource = this._dataSource as any; + const dataSource = this._dataSource; const filter = this._generateFilterByKey(key); // @ts-expect-error const deferred = new Deferred(); const isGroupKey = Array.isArray(key); - const group = dataSource.group(); - if (isGroupKey) { + if (isGroupKey || !dataSource) { return deferred.resolve(-1).promise(); } + const group = dataSource.group(); + + // @ts-expect-error badly typed DataSourceAdapter if (!dataSource._grouping._updatePagingOptions) { this._calculateGlobalRowIndexByFlatData(key, null, true) .done(deferred.resolve) @@ -110,12 +112,14 @@ const data = (Base: DataControllerBase) => class FocusDataControllerExtender ext filter: this._concatWithCombinedFilter(filter), group, }).done((data) => { + // @ts-expect-error badly typed DataSourceAdapter const hasData = isDefined(data) && data.length > 0; if (this._dataSource !== dataSource || !hasData) { return deferred.resolve(-1).promise(); } + // @ts-expect-error badly typed DataSourceAdapter const groupPath = this._getGroupPath(data, group.length); this._expandGroupByPath(this, groupPath, 0).done(() => { diff --git a/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts index 5ec85b788989..916507cb79dc 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts @@ -147,20 +147,20 @@ export const groupingDataControllerExtender = ( } private collapseAll(groupIndex: number): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dataSource = this._dataSource as any; + const dataSource = this._dataSource; + // @ts-expect-error badly typed DataSourceAdapter if (dataSource?.collapseAll(groupIndex)) { - dataSource.pageIndex(0); - dataSource.reload(); + dataSource?.pageIndex(0); + dataSource?.reload(); } } private expandAll(groupIndex: number): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dataSource = this._dataSource as any; + const dataSource = this._dataSource; + // @ts-expect-error badly typed DataSourceAdapter if (dataSource?.expandAll(groupIndex)) { - dataSource.pageIndex(0); - dataSource.reload(); + dataSource?.pageIndex(0); + dataSource?.reload(); } } @@ -184,8 +184,7 @@ export const groupingDataControllerExtender = ( } protected changeRowExpandCore(key: RowKey): DeferredObj { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dataSource = this._dataSource as any; + const dataSource = this._dataSource; const d = Deferred(); if (!dataSource) { @@ -202,8 +201,8 @@ export const groupingDataControllerExtender = ( } private isRowExpanded(key: RowKey): boolean { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return !!(this._dataSource as any)?.isRowExpanded(key); + // @ts-expect-error badly typed DataSourceAdapter + return !!this._dataSource?.isRowExpanded(key); } private expandRow(key: RowKey): DeferredObj { 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 88feac021f82..8cf597ad96f3 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,8 +43,8 @@ export const summaryDataControllerExtender = ( public getTotalSummaryValue(summaryItemName?: string | number | null): unknown { const summaryItemIndex = getSummaryItemIndex(this.option('summary.totalItems'), summaryItemName); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const aggregates = (this._dataSource as any).totalAggregates(); + // @ts-expect-error badly typed DataSourceAdapter + const aggregates = this._dataSource.totalAggregates(); if (aggregates.length && summaryItemIndex > -1) { return aggregates[summaryItemIndex]; @@ -294,8 +294,8 @@ export const summaryDataControllerExtender = ( this._footerItems = []; if (dataSource && summaryTotalItems?.length) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const totalAggregates = (dataSource as any).totalAggregates(); + // @ts-expect-error badly typed DataSourceAdapter + const totalAggregates = dataSource.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 a6f6f23f3de2..7dd43ecde7ff 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 @@ -33,7 +33,6 @@ import type { CallbackFlags, DataChange, DataFilter, - DataSourceAdapterLike, GeneratedItem, ItemChange, ItemProcessingOptions, @@ -333,8 +332,7 @@ export class DataController extends modules.Controller { } public getDataSource(): DataSource | null | undefined { - const adapter = this._dataSource as unknown as DataSourceAdapterLike | null | undefined; - return adapter ? adapter._dataSource : null; + return this._dataSource?._dataSource; } public getCombinedFilter(returnDataField?: boolean): DataFilter { @@ -593,7 +591,7 @@ export class DataController extends modules.Controller { errors.log('W1005', this.component.NAME); this._applyFilter(); } else { - this._currentOperationTypes = dataSource.operationTypes() ?? null; + this._currentOperationTypes = dataSource.operationTypes(); const change: DataChange = isDefined(e) ? { @@ -729,7 +727,7 @@ export class DataController extends modules.Controller { dataSource.load().done((...args: unknown[]) => { this._isPaging = false; result.resolve(...args); - }).fail(result.reject as (...args: unknown[]) => void); + }).fail((...args: unknown[]) => { result.reject(...args); }); } else { result.resolve(); } @@ -1631,12 +1629,11 @@ export class DataController extends modules.Controller { this._skipProcessingPagingChange = false; } - const pageIndex = dataSource.pageIndex() as unknown as number; + // @ts-expect-error badly typed DataSourceAdapter + const pageIndex: number = dataSource.pageIndex(); this._isPaging = optionName === 'pageIndex'; - const loadResult: DeferredObj = ( - dataSource[optionName === 'pageIndex' ? 'load' : 'reload'] as () => DeferredObj - )(); + const loadResult: DeferredObj = dataSource[optionName === 'pageIndex' ? 'load' : 'reload'](); return loadResult.done(() => { this._isPaging = false; @@ -1784,7 +1781,8 @@ export class DataController extends modules.Controller { } public push(...args: unknown[]): unknown { - return (this._dataSource?.push as ((...a: unknown[]) => unknown) | undefined)?.(...args); + // @ts-expect-error badly typed DataSourceAdapter + return this._dataSource?.push(...args); } private itemsCount(): number { 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 d9b1c7578b9f..cb1e8a93b543 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 @@ -29,7 +29,7 @@ import type { import { normalizeRemoteOperations } from './utils/remoteOperations'; export default class DataSourceAdapter extends modules.Controller { - protected _dataSource!: DataSource; + public _dataSource!: DataSource; private _remoteOperations!: RemoteOperationsOptions; @@ -99,6 +99,70 @@ export default class DataSourceAdapter extends modules.Controller { private changingHandlerProxy!: (e: ChangingEvent) => void; + public init(dataSource?: DataSource): void { + if (!dataSource) { + return; + } + + this._dataSource = dataSource; + this._remoteOperations = normalizeRemoteOperations( + this.option('remoteOperations'), + dataSource.store(), + ); + + this._isLastPage = !dataSource.isLastPage(); + this._hasLastPage = false; + this._currentTotalCount = 0; + this._cachedData = createEmptyCachedData(); + this._lastOperationTypes = {}; + this._eventsStrategy = dataSource._eventsStrategy; + this._totalCountCorrection = 0; + this._isLoadingAll = false; + + this.changed = Callbacks(); + this.loadingChanged = Callbacks(); + this.loadError = Callbacks(); + this.customizeStoreLoadOptions = Callbacks(); + this.changing = Callbacks(); + this.pushed = Callbacks(); + + this.dataChangedHandlerProxy = this.dataChangedHandler.bind(this); + this.customizeStoreLoadOptionsHandlerProxy = this.customizeStoreLoadOptionsHandler.bind(this); + this.customizeLoadResultHandlerProxy = this.customizeLoadResultHandler.bind(this); + this.loadingChangedHandlerProxy = this.loadingChangedHandler.bind(this); + this.loadErrorHandlerProxy = this.loadErrorHandler.bind(this); + this.pushHandlerProxy = this.pushHandler.bind(this); + this.changingHandlerProxy = this.changingHandler.bind(this); + + dataSource.on('changed', this.dataChangedHandlerProxy); + dataSource.on('customizeStoreLoadOptions', this.customizeStoreLoadOptionsHandlerProxy); + dataSource.on('customizeLoadResult', this.customizeLoadResultHandlerProxy); + dataSource.on('loadingChanged', this.loadingChangedHandlerProxy); + dataSource.on('loadError', this.loadErrorHandlerProxy); + dataSource.on('changing', this.changingHandlerProxy); + dataSource.store().on('beforePush', this.pushHandlerProxy); + } + + public dispose(isSharedDataSource?: boolean): void { + const dataSource = this._dataSource; + const store = dataSource.store(); + + dataSource.off('changed', this.dataChangedHandlerProxy); + dataSource.off('customizeStoreLoadOptions', this.customizeStoreLoadOptionsHandlerProxy); + dataSource.off('customizeLoadResult', this.customizeLoadResultHandlerProxy); + dataSource.off('loadingChanged', this.loadingChangedHandlerProxy); + dataSource.off('loadError', this.loadErrorHandlerProxy); + dataSource.off('changing', this.changingHandlerProxy); + store?.off('beforePush', this.pushHandlerProxy); + + if (!isSharedDataSource) { + dataSource.dispose(); + } + } + + /** + * @extended: TreeLists's data_source_adapter + */ public filter(): StoreLoadOptions['filter']; public filter(filterExpr: StoreLoadOptions['filter']): void; public filter(...args: unknown[]): unknown { @@ -169,72 +233,6 @@ export default class DataSourceAdapter extends modules.Controller { (this._dataSource as unknown as { cancelAll: () => void }).cancelAll(); } - public init(dataSource?: DataSource): void { - if (!dataSource) { - return; - } - - const that = this; - - that._dataSource = dataSource; - that._remoteOperations = normalizeRemoteOperations( - this.option('remoteOperations'), - dataSource.store(), - ); - - that._isLastPage = !dataSource.isLastPage(); - that._hasLastPage = false; - that._currentTotalCount = 0; - that._cachedData = createEmptyCachedData(); - that._lastOperationTypes = {}; - that._eventsStrategy = dataSource._eventsStrategy; - that._totalCountCorrection = 0; - that._isLoadingAll = false; - - that.changed = Callbacks(); - that.loadingChanged = Callbacks(); - that.loadError = Callbacks(); - that.customizeStoreLoadOptions = Callbacks(); - that.changing = Callbacks(); - that.pushed = Callbacks(); - - that.dataChangedHandlerProxy = that.dataChangedHandler.bind(that); - that.customizeStoreLoadOptionsHandlerProxy = that.customizeStoreLoadOptionsHandler.bind(that); - that.customizeLoadResultHandlerProxy = that.customizeLoadResultHandler.bind(that); - that.loadingChangedHandlerProxy = that.loadingChangedHandler.bind(that); - that.loadErrorHandlerProxy = that.loadErrorHandler.bind(that); - that.pushHandlerProxy = that.pushHandler.bind(that); - that.changingHandlerProxy = that.changingHandler.bind(that); - - dataSource.on('changed', that.dataChangedHandlerProxy); - dataSource.on('customizeStoreLoadOptions', that.customizeStoreLoadOptionsHandlerProxy); - dataSource.on('customizeLoadResult', that.customizeLoadResultHandlerProxy); - dataSource.on('loadingChanged', that.loadingChangedHandlerProxy); - dataSource.on('loadError', that.loadErrorHandlerProxy); - dataSource.on('changing', that.changingHandlerProxy); - dataSource.store().on('beforePush', that.pushHandlerProxy); - } - - public dispose(isSharedDataSource?: boolean): void { - const dataSource = this._dataSource; - const store = dataSource.store(); - - dataSource.off('changed', this.dataChangedHandlerProxy); - dataSource.off('customizeStoreLoadOptions', this.customizeStoreLoadOptionsHandlerProxy); - dataSource.off('customizeLoadResult', this.customizeLoadResultHandlerProxy); - dataSource.off('loadingChanged', this.loadingChangedHandlerProxy); - dataSource.off('loadError', this.loadErrorHandlerProxy); - dataSource.off('changing', this.changingHandlerProxy); - store?.off('beforePush', this.pushHandlerProxy); - - if (!isSharedDataSource) { - dataSource.dispose(); - } - } - - /** - * @extended: TreeLists's data_source_adapter - */ public remoteOperations(): RemoteOperationsOptions { return this._remoteOperations; } @@ -243,13 +241,12 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling */ public refresh(options, operationTypes) { - const that = this; - const dataSource = that._dataSource; + const dataSource = this._dataSource; if (operationTypes.reload) { - that.resetCurrentTotalCount(); - that._isLastPage = !dataSource.paginate(); - that._hasLastPage = that._isLastPage; + this.resetCurrentTotalCount(); + this._isLastPage = !dataSource.paginate(); + this._hasLastPage = this._isLastPage; } } @@ -766,11 +763,9 @@ export default class DataSourceAdapter extends modules.Controller { } private _scheduleCustomLoadCallbacks(deferred) { - const that = this; - - that._isCustomLoading = true; + this._isCustomLoading = true; deferred.always(() => { - that._isCustomLoading = false; + this._isCustomLoading = false; }); } @@ -778,8 +773,8 @@ export default class DataSourceAdapter extends modules.Controller { return this._loadingOperationTypes; } - public operationTypes(): OperationTypes | undefined { - return this._operationTypes; + public operationTypes(): OperationTypes | null { + return this._operationTypes ?? null; } public lastLoadOptions() { @@ -850,9 +845,8 @@ export default class DataSourceAdapter extends modules.Controller { } public pageCount() { - const that = this; - const count = that.totalItemsCount() - that._totalCountCorrection; - const pageSize = that.pageSize(); + const count = this.totalItemsCount() - this._totalCountCorrection; + const pageSize = this.pageSize(); if (pageSize && count > 0) { return Math.max(1, Math.ceil(count / pageSize)); @@ -892,8 +886,7 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling */ public load(options?): DeferredObj { - const that = this; - const dataSource = that._dataSource; + const dataSource = this._dataSource; const d = Deferred(); if (options) { @@ -913,20 +906,20 @@ export default class DataSourceAdapter extends modules.Controller { this._isLoadingAll = options.isLoadingAll; - that._scheduleCustomLoadCallbacks(d); + this._scheduleCustomLoadCallbacks(d); dataSource._scheduleLoadCallbacks(d); - that.customizeStoreLoadOptionsHandler(loadResult); + this.customizeStoreLoadOptionsHandler(loadResult); executeTask(() => { if (!dataSource.store()) { d.reject('canceled'); return; } - when(loadResult.data || that.loadFromStore(loadResult.storeLoadOptions)).done((data, extra) => { + when(loadResult.data || this.loadFromStore(loadResult.storeLoadOptions)).done((data, extra) => { loadResult.data = data; loadResult.extra = extra || {}; - that.customizeLoadResultHandler(loadResult); + this.customizeLoadResultHandler(loadResult); if (options.requireTotalCount && loadResult.extra.totalCount === undefined) { loadResult.extra.totalCount = store.totalCount(loadResult.storeLoadOptions); @@ -937,10 +930,10 @@ export default class DataSourceAdapter extends modules.Controller { d.resolve(data, loadResult.extra); }).fail((e) => { d.reject(e); }); }).fail((e) => { d.reject(e); }); - }, that.option('loadingTimeout')); + }, this.option('loadingTimeout')); return d.fail(function () { - that._eventsStrategy.fireEvent('loadError', arguments); + this._eventsStrategy.fireEvent('loadError', arguments); }).always(() => { this._isLoadingAll = false; }).promise() as unknown as DeferredObj; 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 e24d0d55a716..aa3d5fe659dc 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 })); } From f712140fb3f6b62232f95b4f2f60be8e52c96e04 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:36:48 +0400 Subject: [PATCH 08/14] revert(data): restore DataSource enumerable-member shim - viz/vectorMap relies on it too --- .../__internal/data/data_source/data_source.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/devextreme/js/__internal/data/data_source/data_source.ts b/packages/devextreme/js/__internal/data/data_source/data_source.ts index 72aae3df3fab..79350d094d78 100644 --- a/packages/devextreme/js/__internal/data/data_source/data_source.ts +++ b/packages/devextreme/js/__internal/data/data_source/data_source.ts @@ -788,3 +788,21 @@ export class DataSource { return this; } } + +/* + * `Class.inherit()` defined prototype members as enumerable, and consumers still rely on + * that: the grid's DataSourceAdapter copies a data source's members with a `for…in` loop + * (see its "remove copying dataSource's members" TODO). ES6 class methods are not + * enumerable, so restore the descriptors a data source used to expose. + */ +Object.getOwnPropertyNames(DataSource.prototype).forEach((memberName) => { + if (memberName === 'constructor') { + return; + } + + const descriptor = Object.getOwnPropertyDescriptor(DataSource.prototype, memberName); + + if (descriptor) { + Object.defineProperty(DataSource.prototype, memberName, { ...descriptor, enumerable: true }); + } +}); From e8fad5919a1a0e8168dddcbdbc9d687e69fbac82 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 18:31:57 +0400 Subject: [PATCH 09/14] fix(dataController): bind adapter this in loadAll error handler --- .../grid_core/data_source_adapter/m_data_source_adapter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 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 cb1e8a93b543..bc812cd3b59b 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 @@ -932,8 +932,8 @@ export default class DataSourceAdapter extends modules.Controller { }).fail((e) => { d.reject(e); }); }, this.option('loadingTimeout')); - return d.fail(function () { - this._eventsStrategy.fireEvent('loadError', arguments); + return d.fail((...args: unknown[]) => { + this._eventsStrategy.fireEvent('loadError', args); }).always(() => { this._isLoadingAll = false; }).promise() as unknown as DeferredObj; From 3775d9eef8a590d4ff444860ea42670ed5634794 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:32:21 +0400 Subject: [PATCH 10/14] fix(dataController): getDataSource returns null not undefined when no adapter --- .../grids/grid_core/data_controller/data_controller.ts | 4 ++-- 1 file changed, 2 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 7dd43ecde7ff..35e7608b0f64 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 @@ -331,8 +331,8 @@ export class DataController extends modules.Controller { return !this._isLoading; } - public getDataSource(): DataSource | null | undefined { - return this._dataSource?._dataSource; + public getDataSource(): DataSource | null { + return this._dataSource?._dataSource ?? null; } public getCombinedFilter(returnDataField?: boolean): DataFilter { From 55757565b785a0693a64b6b18fd94fceaea37567 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 22:33:18 +0400 Subject: [PATCH 11/14] refactor(data): drop DataSource enumerable-member shim - no consumers left after adapter de-proxy --- .../__internal/data/data_source/data_source.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/packages/devextreme/js/__internal/data/data_source/data_source.ts b/packages/devextreme/js/__internal/data/data_source/data_source.ts index 79350d094d78..72aae3df3fab 100644 --- a/packages/devextreme/js/__internal/data/data_source/data_source.ts +++ b/packages/devextreme/js/__internal/data/data_source/data_source.ts @@ -788,21 +788,3 @@ export class DataSource { return this; } } - -/* - * `Class.inherit()` defined prototype members as enumerable, and consumers still rely on - * that: the grid's DataSourceAdapter copies a data source's members with a `for…in` loop - * (see its "remove copying dataSource's members" TODO). ES6 class methods are not - * enumerable, so restore the descriptors a data source used to expose. - */ -Object.getOwnPropertyNames(DataSource.prototype).forEach((memberName) => { - if (memberName === 'constructor') { - return; - } - - const descriptor = Object.getOwnPropertyDescriptor(DataSource.prototype, memberName); - - if (descriptor) { - Object.defineProperty(DataSource.prototype, memberName, { ...descriptor, enumerable: true }); - } -}); From d70ea3ea21a2e7490bc053b59c72772ab56ecd1a Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Mon, 31 Aug 2026 23:13:22 +0400 Subject: [PATCH 12/14] Revert: restore DataSource enumerable-member shim - viz stubClass test helper needs it --- .../__internal/data/data_source/data_source.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/devextreme/js/__internal/data/data_source/data_source.ts b/packages/devextreme/js/__internal/data/data_source/data_source.ts index 72aae3df3fab..79350d094d78 100644 --- a/packages/devextreme/js/__internal/data/data_source/data_source.ts +++ b/packages/devextreme/js/__internal/data/data_source/data_source.ts @@ -788,3 +788,21 @@ export class DataSource { return this; } } + +/* + * `Class.inherit()` defined prototype members as enumerable, and consumers still rely on + * that: the grid's DataSourceAdapter copies a data source's members with a `for…in` loop + * (see its "remove copying dataSource's members" TODO). ES6 class methods are not + * enumerable, so restore the descriptors a data source used to expose. + */ +Object.getOwnPropertyNames(DataSource.prototype).forEach((memberName) => { + if (memberName === 'constructor') { + return; + } + + const descriptor = Object.getOwnPropertyDescriptor(DataSource.prototype, memberName); + + if (descriptor) { + Object.defineProperty(DataSource.prototype, memberName, { ...descriptor, enumerable: true }); + } +}); From 8ea8b078713dd9b03e839651c774e685deec2661 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Tue, 1 Sep 2026 00:32:27 +0400 Subject: [PATCH 13/14] refactor(data): drop DataSource enumerable shim; teach viz stubClass to stub non-enumerable proto methods --- .../data/data_source/data_source.ts | 18 ------------- .../devextreme/testing/helpers/vizMocks.js | 26 +++++++++++++------ 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/packages/devextreme/js/__internal/data/data_source/data_source.ts b/packages/devextreme/js/__internal/data/data_source/data_source.ts index 79350d094d78..72aae3df3fab 100644 --- a/packages/devextreme/js/__internal/data/data_source/data_source.ts +++ b/packages/devextreme/js/__internal/data/data_source/data_source.ts @@ -788,21 +788,3 @@ export class DataSource { return this; } } - -/* - * `Class.inherit()` defined prototype members as enumerable, and consumers still rely on - * that: the grid's DataSourceAdapter copies a data source's members with a `for…in` loop - * (see its "remove copying dataSource's members" TODO). ES6 class methods are not - * enumerable, so restore the descriptors a data source used to expose. - */ -Object.getOwnPropertyNames(DataSource.prototype).forEach((memberName) => { - if (memberName === 'constructor') { - return; - } - - const descriptor = Object.getOwnPropertyDescriptor(DataSource.prototype, memberName); - - if (descriptor) { - Object.defineProperty(DataSource.prototype, memberName, { ...descriptor, enumerable: true }); - } -}); diff --git a/packages/devextreme/testing/helpers/vizMocks.js b/packages/devextreme/testing/helpers/vizMocks.js index 8a6838ea73a5..ae1a8310d41b 100644 --- a/packages/devextreme/testing/helpers/vizMocks.js +++ b/packages/devextreme/testing/helpers/vizMocks.js @@ -259,14 +259,24 @@ function stubClass(target, members, settings) { settings = settings || {}; proto.prototype = typeof target === 'function' ? target.prototype : target; const stubPrototype = stub.prototype = new proto(); - $.each(stubPrototype, function(name, member) { - if(typeof member === 'function' && name !== 'constructor') { - stubPrototype[name] = function() { - createStub(this, name); - return this[name].apply(this, arguments); - }; - } - }); + // Walk the prototype chain so non-enumerable methods (ES6 class methods) are + // stubbed too; a plain `for...in`/`$.each` only sees enumerable members. + const stubbedNames = {}; + for(let currentProto = stubPrototype; currentProto && currentProto !== Object.prototype; currentProto = Object.getPrototypeOf(currentProto)) { + Object.getOwnPropertyNames(currentProto).forEach(function(name) { + if(name === 'constructor' || stubbedNames[name]) { + return; + } + const descriptor = Object.getOwnPropertyDescriptor(currentProto, name); + if(descriptor && typeof descriptor.value === 'function') { + stubbedNames[name] = true; + stubPrototype[name] = function() { + createStub(this, name); + return this[name].apply(this, arguments); + }; + } + }); + } settings.$extraFunctions && $.each(settings.$extraFunctions, function(_, name) { _members[name] = 'name' in _members ? _members[name] : function() { }; }); From ff0ffd553e7119747de71e490a13666f2aa75a80 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Tue, 1 Sep 2026 14:19:14 +0400 Subject: [PATCH 14/14] refactor(dataController): type adapter delegate params; replace as any with real types / narrow casts per review --- .../virtual_scrolling_data_controller.ts | 44 ++++++++++--------- .../virtual_scrolling/m_virtual_scrolling.ts | 23 ++++++---- .../virtual_scrolling/utils/items.ts | 2 +- .../data_controller/m_data_controller.ts | 3 +- .../js/__internal/grids/tree_list/m_focus.ts | 6 ++- .../grids/tree_list/m_virtual_scrolling.ts | 3 +- 6 files changed, 47 insertions(+), 34 deletions(-) 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 0efa6e09c494..ed08c807aeda 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 @@ -37,6 +37,7 @@ import { import type { dataSourceAdapterExtender } from '../m_virtual_scrolling'; import { VirtualScrollController } from '../m_virtual_scrolling_core'; import type { ChangedLoadParams } from '../types'; +import type { GroupCountableDataSource } from '../utils/items'; import { correctCount, isItemCountableByDataSource, @@ -111,7 +112,8 @@ 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 as any)?.getItemIndexByPosition(); + // @ts-expect-error badly typed DataSourceAdapter + const itemIndex = rowsScrollController?.getItemIndexByPosition(); const result = super.reload.apply(this, arguments as any); return result?.done(() => { if (isVirtualMode(this) || gridCoreUtils.isVirtualRowRendering(this)) { @@ -180,7 +182,7 @@ export const virtualScrollingDataControllerExtender = ( private _getRowsScrollDataOptions() { const that = this; const isItemCountable = function (item) { - return isItemCountableByDataSource(item, that._dataSource as any); + return isItemCountableByDataSource(item, that._dataSource as unknown as GroupCountableDataSource); }; return { @@ -374,7 +376,7 @@ export const virtualScrollingDataControllerExtender = ( processedItems.forEach((item) => { const { rowType } = item; - const itemCountable = isItemCountableByDataSource(item, dataSource as any); + const itemCountable = isItemCountableByDataSource(item, dataSource as unknown as GroupCountableDataSource); const isNextGroupItem = rowType === 'group' && (prevCountable || (prevRowType !== 'group' && currentIndex > 0)); const isNextDataItem = rowType === 'data' && itemCountable && (prevCountable || prevRowType !== 'group'); @@ -408,7 +410,7 @@ export const virtualScrollingDataControllerExtender = ( } protected _afterProcessItems(processedItems: ProcessedItem[]): ProcessedItem[] { - this._itemCount = processedItems.filter((item) => isItemCountableByDataSource(item, this._dataSource as any)).length; + this._itemCount = processedItems.filter((item) => isItemCountableByDataSource(item, this._dataSource as unknown as GroupCountableDataSource)).length; if (isDefined(this._loadViewportParams)) { this._updateLoadViewportParams(); @@ -443,7 +445,7 @@ export const virtualScrollingDataControllerExtender = ( if (removeCount) { const fromEnd = changeType === 'prepend'; - removeCount = correctCount(that._items, removeCount, fromEnd, (item, isNextAfterLast) => isItemCountableByDataSource(item, that._dataSource as any) || (item.rowType === 'group' && isNextAfterLast)); + removeCount = correctCount(that._items, removeCount, fromEnd, (item, isNextAfterLast) => isItemCountableByDataSource(item, that._dataSource as unknown as GroupCountableDataSource) || (item.rowType === 'group' && isNextAfterLast)); change.removeCount = removeCount; } @@ -532,46 +534,46 @@ export const virtualScrollingDataControllerExtender = ( return isDefined(lastVisibleItem?.dataIndex) ? lastVisibleItem!.dataIndex + 1 : 0; } - private viewportSize() { + private viewportSize(size?) { const rowsScrollController = this._rowsScrollController; const dataSource = this._dataSource; // @ts-expect-error - const result = rowsScrollController?.viewportSize.apply(rowsScrollController, arguments); + const result = rowsScrollController?.viewportSize(size); if (this.option(LEGACY_SCROLLING_MODE) === false) { return result; } - return dataSource?.viewportSize.apply(dataSource, arguments as any); + return dataSource?.viewportSize(size); } private viewportHeight(height, scrollTop) { this._rowsScrollController?.viewportHeight(height, scrollTop); } - private viewportItemSize() { + private viewportItemSize(size?) { const rowsScrollController = this._rowsScrollController; const dataSource = this._dataSource; // @ts-expect-error - const result = rowsScrollController?.viewportItemSize.apply(rowsScrollController, arguments); + const result = rowsScrollController?.viewportItemSize(size); if (this.option(LEGACY_SCROLLING_MODE) === false) { return result; } - return dataSource?.viewportItemSize.apply(dataSource, arguments as any); + return dataSource?.viewportItemSize(size); } - private setViewportPosition() { + private setViewportPosition(position?) { const rowsScrollController = this._rowsScrollController; const dataSource = this._dataSource; this._isPaging = false; if (rowsScrollController) { // @ts-expect-error - rowsScrollController.setViewportPosition.apply(rowsScrollController, arguments); + rowsScrollController.setViewportPosition(position); } else { - dataSource?.setViewportPosition.apply(dataSource, arguments as any); + dataSource?.setViewportPosition(position); } } @@ -832,11 +834,11 @@ export const virtualScrollingDataControllerExtender = ( if (rowsScrollController) { // @ts-expect-error - return rowsScrollController.getItemSize.apply(rowsScrollController, arguments); + return rowsScrollController.getItemSize(); } const dataSource = this._dataSource; - return dataSource?.getItemSize.apply(dataSource, arguments as any); + return dataSource?.getItemSize(); } private getItemSizes() { @@ -844,23 +846,23 @@ export const virtualScrollingDataControllerExtender = ( if (rowsScrollController) { // @ts-expect-error - return rowsScrollController.getItemSizes.apply(rowsScrollController, arguments); + return rowsScrollController.getItemSizes(); } const dataSource = this._dataSource; - return dataSource?.getItemSizes.apply(dataSource, arguments as any); + return dataSource?.getItemSizes(); } - private getContentOffset() { + private getContentOffset(type?) { const rowsScrollController = this._rowsScrollController; if (rowsScrollController) { // @ts-expect-error - return rowsScrollController.getContentOffset.apply(rowsScrollController, arguments); + return rowsScrollController.getContentOffset(type); } const dataSource = this._dataSource; - return dataSource?.getContentOffset.apply(dataSource, arguments as any); + return dataSource?.getContentOffset(type); } public refresh(options?: boolean | RefreshOptions): DeferredObj { 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 a5253cf9b059..094de621b840 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 @@ -33,6 +33,7 @@ import { VIRTUAL_ROW_CLASS, } from './const'; import { subscribeToExternalScrollers, VirtualScrollController } from './m_virtual_scrolling_core'; +import type { GroupCountableDataSource } from './utils/items'; import { isItemCountableByDataSource } from './utils/items'; import { isInfiniteMode, isVirtualMode, isVirtualPaging } from './utils/scrolling_mode'; @@ -362,7 +363,8 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return proxyDataSourceAdapterMethod(this, 'virtualItemsCount', [...arguments]); } - public getContentOffset(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public getContentOffset(type?): any { return proxyDataSourceAdapterMethod(this, 'getContentOffset', [...arguments]); } @@ -375,7 +377,8 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return proxyDataSourceAdapterMethod(this, 'setContentItemSizes', [...arguments]); } - public setViewportPosition(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public setViewportPosition(position?): any { return proxyDataSourceAdapterMethod(this, 'setViewportPosition', [...arguments]); } @@ -392,11 +395,13 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return proxyDataSourceAdapterMethod(this, 'getItemIndexByPosition', [...arguments]); } - public viewportSize(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public viewportSize(size?): any { return proxyDataSourceAdapterMethod(this, 'viewportSize', [...arguments]); } - public viewportItemSize(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public viewportItemSize(size?): any { return proxyDataSourceAdapterMethod(this, 'viewportItemSize', [...arguments]); } @@ -570,7 +575,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo } protected _renderCore(e) { - const startRenderTime: any = new Date(); + const startRenderTime = Date.now(); const deferred = super._renderCore.apply(this, arguments as any); @@ -583,9 +588,11 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo .viewportSize() || 20; if (gridCoreUtils.isVirtualRowRendering(this) && itemCount > 0 && this.option(LEGACY_SCROLLING_MODE) !== false) { - (dataSource as any)._renderTime = ((new Date()) as any - startRenderTime) * viewportSize / itemCount; + // @ts-expect-error badly typed DataSourceAdapter + dataSource._renderTime = (Date.now() - startRenderTime) * viewportSize / itemCount; } else { - (dataSource as any)._renderTime = ((new Date()) as any - startRenderTime); + // @ts-expect-error badly typed DataSourceAdapter + dataSource._renderTime = Date.now() - startRenderTime; } } return deferred; @@ -719,7 +726,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo itemSize = 0; } lastLoadIndex = currentItem.loadIndex; - } else if (isItemCountableByDataSource(currentItem, dataSource as any)) { + } else if (isItemCountableByDataSource(currentItem, dataSource as unknown as GroupCountableDataSource)) { if (firstCountableItem) { firstCountableItem = false; } else { diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts index fc8b52d079dc..28412664c581 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts @@ -1,6 +1,6 @@ import type { ProcessedItem } from '@ts/grids/grid_core/data_controller/types'; -interface GroupCountableDataSource { +export interface GroupCountableDataSource { isGroupItemCountable: (data: unknown) => boolean; } 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 ae9a248a14e4..55c9e35e78fa 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 @@ -166,7 +166,8 @@ export class TreeListDataController extends DataController { break; case 'expandedRowKeys': case 'onNodesInitialized': - if (this._dataSource && !(this._dataSource as any)._isNodesInitializing && !equalByValue(args.value, args.previousValue)) { + // @ts-expect-error badly typed DataSourceAdapter + if (this._dataSource && !this._dataSource._isNodesInitializing && !equalByValue(args.value, args.previousValue)) { this._loadOnOptionChange(); } args.handled = true; 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 523812f655be..976b33b0d7d0 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts @@ -85,10 +85,12 @@ const data = ( that.getParentKey(key).done((parentKey) => { if (dataSource && parentKey !== undefined && parentKey !== that.option('rootValue')) { - (dataSource as any)._isNodesInitializing = true; + // @ts-expect-error badly typed DataSourceAdapter + dataSource._isNodesInitializing = true; // @ts-expect-error that.expandRow(parentKey); - (dataSource as any)._isNodesInitializing = false; + // @ts-expect-error badly typed DataSourceAdapter + dataSource._isNodesInitializing = false; that.expandAscendants(parentKey).done(d.resolve).fail(d.reject); } else { d.resolve(); 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 a314864dd925..169ec0172d0a 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,8 @@ virtualScrollingModule.extenders.views.rowsView = (Base: ModuleType) = virtualScrollingModule.extenders.controllers.data = (Base: ModuleType) => class TreeListVirtualScrollingDataControllerExtender extends virtualScrollingDataControllerExtender(Base) { protected _loadOnOptionChange() { - const virtualScrollController = (this._dataSource as any)?._virtualScrollController; + // @ts-expect-error badly typed DataSourceAdapter + const virtualScrollController = this._dataSource?._virtualScrollController; virtualScrollController?.reset(); // @ts-expect-error