Skip to content

Commit

Permalink
address the scenario when extrenal type parameter is passed to DeepPa…
Browse files Browse the repository at this point in the history
…rtial cond type
  • Loading branch information
VasilyStrelyaev committed Jan 15, 2025
1 parent dbecbe0 commit d8e4b81
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 48 deletions.
72 changes: 72 additions & 0 deletions e2e/compilation-cases/T1263537.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
ODataStore, CustomStore, Store, LoadOptions,
} from 'devextreme/common/data';

import { DeepPartial } from 'devextreme/common';

// Remove the 'ts-expect-error' below to see the current issue:
// Entity is not compatible with DeepPartial<Entity>
function initCustomStore<Entity, Id>(oDataStore: ODataStore<Entity, Id>): Store<Entity, Id> {
const customStore = new CustomStore<Entity, Id>({
key: 'id',
byKey: (key: Id) => oDataStore.byKey(key),
insert: (e: Entity) => oDataStore.insert(e),
load: (options: LoadOptions<Entity>) => oDataStore.load(options),
remove: (key: Id) => oDataStore.remove(key),
totalCount: (obj) => oDataStore.totalCount(obj),
// @ts-expect-error - The initial issue
update: (key: Id, updated: Entity) => oDataStore.update(key, updated),
});
return customStore;
}

// If this TS issue is fixed: https://github.com/microsoft/TypeScript/issues/23132
// there will be a good workaround to use type constraints to make such an assignment possible
function initCustomStore3<Entity extends object, Id>(
oDataStore: ODataStore<Entity, Id>,
): Store<Entity, Id> {
const customStore = new CustomStore<Entity, Id>({
key: 'id',
byKey: (key: Id) => oDataStore.byKey(key),
insert: (e: Entity) => oDataStore.insert(e),
load: (options: LoadOptions<Entity>) => oDataStore.load(options),
remove: (key: Id) => oDataStore.remove(key),
totalCount: (obj) => oDataStore.totalCount(obj),
// @ts-expect-error - How it will hopefully work in TypeScript 5.8.0+
update: (key: Id, updated: Entity) => oDataStore.update(key, updated),
});
return customStore;
}

// Currenlty, we can only publish DeepPartial, which will be a black box
// equal to only itself when initialized with a type parameter.
// Users will be able to make DeepPartial<ExternalTypeParameter> type to avoid the TS error.
function initCustomStore4<Entity, Id>(oDataStore: ODataStore<Entity, Id>): Store<Entity, Id> {
const customStore = new CustomStore<Entity, Id>({
key: 'id',
byKey: (key: Id) => oDataStore.byKey(key),
insert: (e: Entity) => oDataStore.insert(e),
load: (options: LoadOptions<Entity>) => oDataStore.load(options),
remove: (key: Id) => oDataStore.remove(key),
totalCount: (obj) => oDataStore.totalCount(obj),
update: (key: Id, updated: DeepPartial<Entity>) => oDataStore.update(key, updated),
});
return customStore;
}

// Proof that it currently works if we are dealing with resolved types, not type parameters
type Key = number;
type Data = object;

function initCustomStore2(oDataStore: ODataStore<Data, Key>): Store<Data, Key> {
const customStore = new CustomStore<Data, Key>({
key: 'id',
byKey: (key: Key) => oDataStore.byKey(key),
insert: (e: Data) => oDataStore.insert(e),
load: (options: LoadOptions<Data>) => oDataStore.load(options),
remove: (key: Key) => oDataStore.remove(key),
totalCount: (obj) => oDataStore.totalCount(obj),
update: (key: Key, updated: Data) => oDataStore.update(key, updated),
});
return customStore;
}
2 changes: 1 addition & 1 deletion e2e/compilation-cases/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { Permutations } from 'devextreme/core';
const expected32: Expected3 = ANY as Permutations<'a' | 'b' | 'c'>;
}

import { Scalar } from 'devextreme/core';
import { Scalar } from 'devextreme/core/index.types';

{
interface TestInterface { i: any }
Expand Down
4 changes: 3 additions & 1 deletion e2e/compilation-cases/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
"scripts": {
"test": "tsc --noEmit"
},
"dependencies": {
"devextreme": "workspace:*"
},
"devDependencies": {
"@angular/common": "11.2.14",
"@types/jquery": "3.5.29",
"devextreme": "workspace:*",
"jquery": "3.7.1",
"typescript": "4.9.5"
}
Expand Down
1 change: 1 addition & 0 deletions packages/devextreme-angular/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {
CustomRule,
DataStructure,
DataType,
DeepPartial,
DefaultOptionsRule,
Direction,
DisplayMode,
Expand Down
1 change: 1 addition & 0 deletions packages/devextreme-react/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {
CustomRule,
DataStructure,
DataType,
DeepPartial,
DefaultOptionsRule,
Direction,
DisplayMode,
Expand Down
1 change: 1 addition & 0 deletions packages/devextreme-vue/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {
CustomRule,
DataStructure,
DataType,
DeepPartial,
DefaultOptionsRule,
Direction,
DisplayMode,
Expand Down
6 changes: 3 additions & 3 deletions packages/devextreme/js/__internal/ui/chat/messagelist.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type {
DeepPartial,
} from '@js/common';
import { Guid } from '@js/common';
import type { Format } from '@js/common/core/localization';
import dateLocalization from '@js/common/core/localization/date';
import messageLocalization from '@js/common/core/localization/message';
import type {
DeepPartial,
} from '@js/core/index';
import type { dxElementWrapper } from '@js/core/renderer';
import $ from '@js/core/renderer';
import resizeObserverSingleton from '@js/core/resize_observer';
Expand Down
16 changes: 11 additions & 5 deletions packages/devextreme/js/common.d.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { PositionConfig } from './common/core/animation';

import type {
Scalar,
OmitInternal,
} from './core';
} from './core/index.types';

import {
Device,
} from './common/core/environment';

import {
DeepPartial,
} from './core';

import type dxDraggable from './ui/draggable';
import type dxScrollable from './ui/scroll_view/ui.scrollable';
import type dxSortable from './ui/sortable';
Expand Down Expand Up @@ -884,6 +882,14 @@ export type DefaultOptionsRule<T> = {
options: DeepPartial<T>;
};

/**
* @public
* @namespace DevExpress.common
*/
export type DeepPartial<T> = T extends Scalar ? T : {
[P in keyof T]?: DeepPartial<T[P]>;
};

/** @public */
export type FloatingActionButtonDirection = 'auto' | 'up' | 'down';

Expand Down
3 changes: 2 additions & 1 deletion packages/devextreme/js/common/data.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable max-classes-per-file */
import { DeepPartial } from '../common';
import { DxExtendedPromise, DxPromise } from '../core/utils/deferred';
import AbstractStore, { AbstractStoreOptions } from '../data/abstract_store';

Expand Down Expand Up @@ -303,7 +304,7 @@ export type CustomStoreOptions<
* @type_function_return Promise<any>
* @public
*/
update?: ((key: TKey, values: TItem) => PromiseLike<any>);
update?: ((key: TKey, values: DeepPartial<TItem>) => PromiseLike<any>);
/**
* @docid
* @default undefined
Expand Down
5 changes: 1 addition & 4 deletions packages/devextreme/js/common/grids.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@ import {
Sortable,
SortOrder,
ValidationRule,
DeepPartial,
template,
} from '../common';

import {
DeepPartial,
} from '../core/index';

import {
UserDefinedElement,
DxElement,
Expand Down
10 changes: 3 additions & 7 deletions packages/devextreme/js/core/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export { Scalar, OmitInternal } from './index.types';
export { DeepPartial } from '../common';

type KeyOf<T> = T extends never ? never : keyof T;

type KeysOf<T1, T2, T3, T4, T5, T6, T7, T8> =
Expand All @@ -19,11 +22,6 @@ export type Xor<T1, T2 = never, T3 = never, T4 = never, T5 = never, T6 = never,
| Seal<T8, KeysOf<T1, T2, T3, T4, T5, T6, T7, T9>>
| Seal<T9, KeysOf<T1, T2, T3, T4, T5, T6, T7, T8>>;

export type Scalar = undefined | null | string | String | number | Number | bigint | BigInteger | boolean | Boolean | Date | Function | Symbol | Array<unknown>;
export type DeepPartial<T> = T extends Scalar ? T : {
[P in keyof T]?: DeepPartial<T[P]>;
};

type ItemType<T> = T extends (infer TItem)[] ? TItem : T;
type Property<T, TPropName extends string> = T extends Partial<Record<TPropName, infer TValue>> ? TValue : never;
type OwnPropertyType<T, TPropName extends string> = Property<ItemType<T>, TPropName>;
Expand All @@ -33,8 +31,6 @@ export type PropertyType<T, TProp extends string> =
? PropertyType<OwnPropertyType<T, TOwnProp>, TNestedProps>
: OwnPropertyType<T, TProp>;

export type OmitInternal<T> = Omit<T, `${'_' | '$'}${any}`>;

/**
* IncrementalCounter[1]=2, IncrementalCounter[2]=3, IncrementalCounter[3]=4, ...
*/
Expand Down
3 changes: 3 additions & 0 deletions packages/devextreme/js/core/index.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Scalar = undefined | null | string | String | number | Number | bigint | BigInteger | boolean | Boolean | Date | Function | Symbol | Array<unknown>;

export type OmitInternal<T> = Omit<T, `${'_' | '$'}${any}`>;
2 changes: 1 addition & 1 deletion packages/devextreme/js/data/store.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DxPromise, DxExtendedPromise } from '../core/utils/deferred';
import { DeepPartial } from '../core';
import { DeepPartial } from '../common';
import { FilterDescriptor, GroupDescriptor, LoadOptions } from '../common/data';

/**
Expand Down
6 changes: 5 additions & 1 deletion packages/devextreme/ts/aliases.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,10 @@ declare namespace DevExpress {
export class TransitionExecutor extends common.core.animation.TransitionExecutor {}
}

declare namespace DevExpress.core {
export type DeepPartial<T> = common.DeepPartial<T>;
}

declare namespace DevExpress.localization {
export const formatDate: typeof common.core.localization.formatDate;
export const formatMessage: typeof common.core.localization.formatMessage;
Expand Down Expand Up @@ -877,7 +881,7 @@ declare namespace DevExpress.data {
export const query: typeof common.data.query;
export type Query = common.data.Query;
export const setErrorHandler: typeof common.data.setErrorHandler;
export class Store<TItem = any, TKey = any> extends common.data.Store<TItem, TKey>{}
export class Store<TItem = any, TKey = any> extends common.data.Store<TItem, TKey> {}
}

declare namespace DevExpress.data.CustomStore {
Expand Down
29 changes: 13 additions & 16 deletions packages/devextreme/ts/dx.all.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ declare module DevExpress {
| DevExpress.common.core.environment.Device
| DevExpress.common.core.environment.Device[]
| ((device: DevExpress.common.core.environment.Device) => boolean);
options: DevExpress.core.DeepPartial<T>;
options: DevExpress.common.DeepPartial<T>;
};
/**
* [descr:DOMComponent]
Expand Down Expand Up @@ -981,6 +981,11 @@ declare module DevExpress.common {
| 'boolean'
| 'object'
| 'datetime';
export type DeepPartial<T> = T extends DevExpress.core.Scalar
? T
: {
[P in keyof T]?: DeepPartial<T[P]>;
};
export type Direction = 'bottom' | 'left' | 'right' | 'top';
export type DisplayMode = 'adaptive' | 'compact' | 'full';
export type DragDirection = 'both' | 'horizontal' | 'vertical';
Expand Down Expand Up @@ -3047,7 +3052,7 @@ declare module DevExpress.common.data {
/**
* [descr:CustomStoreOptions.update]
*/
update?: (key: TKey, values: TItem) => PromiseLike<any>;
update?: (key: TKey, values: DeepPartial<TItem>) => PromiseLike<any>;
/**
* [descr:CustomStoreOptions.useDefaultSearch]
*/
Expand Down Expand Up @@ -3811,7 +3816,7 @@ declare module DevExpress.common.data {
push(
changes: Array<{
type: 'insert' | 'update' | 'remove';
data?: DevExpress.core.DeepPartial<TItem>;
data?: DeepPartial<TItem>;
key?: TKey;
index?: number;
}>
Expand All @@ -3832,7 +3837,7 @@ declare module DevExpress.common.data {
*/
update(
key: TKey,
values: DevExpress.core.DeepPartial<TItem>
values: DeepPartial<TItem>
): DevExpress.core.utils.DxExtendedPromise<TItem>;
}
/**
Expand Down Expand Up @@ -4432,7 +4437,7 @@ declare module DevExpress.common.grids {
*/
setCellValue?: (
this: ColumnBase,
newData: DevExpress.core.DeepPartial<TRowData>,
newData: DeepPartial<TRowData>,
value: any,
currentRowData: TRowData
) => void | PromiseLike<void>;
Expand Down Expand Up @@ -4765,7 +4770,7 @@ declare module DevExpress.common.grids {
/**
* [descr:DataChange.data]
*/
data: DevExpress.core.DeepPartial<TRowData>;
data: DeepPartial<TRowData>;
/**
* [descr:DataChange.insertAfterKey]
*/
Expand Down Expand Up @@ -6234,7 +6239,7 @@ declare module DevExpress.common.grids {
/**
* [descr:RowUpdatingInfo.newData]
*/
newData: DevExpress.core.DeepPartial<TRowData>;
newData: DeepPartial<TRowData>;
/**
* [descr:RowUpdatingInfo.key]
*/
Expand Down Expand Up @@ -6264,7 +6269,7 @@ declare module DevExpress.common.grids {
/**
* [descr:RowValidatingInfo.newData]
*/
readonly newData: DevExpress.core.DeepPartial<TRowData>;
readonly newData: DeepPartial<TRowData>;
/**
* @docid
* @type object
Expand Down Expand Up @@ -6518,14 +6523,6 @@ declare module DevExpress.core {
left: number;
top: number;
}
/**
* @deprecated Attention! This type is for internal purposes only. If you used it previously, please submit a ticket to our {@link https://supportcenter.devexpress.com/ticket/create Support Center}. We will check if there is an alternative solution.
*/
export type DeepPartial<T> = T extends Scalar
? T
: {
[P in keyof T]?: DeepPartial<T[P]>;
};
/**
* [descr:DevicesObject]
*/
Expand Down
Loading

0 comments on commit d8e4b81

Please sign in to comment.