Skip to content

Commit

Permalink
Fix DeepPartial type (#22789)
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyaKhD authored Sep 30, 2022
1 parent 3f4fcbc commit 0f23421
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 104 deletions.
7 changes: 4 additions & 3 deletions js/core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ 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 DeepPartial<T> = T extends object ? {
[P in keyof T]?: T[P] extends Function ? T[P] : DeepPartial<T[P]>;
} : T;
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;
Expand Down
229 changes: 133 additions & 96 deletions testing/typescript/core.ts
Original file line number Diff line number Diff line change
@@ -1,107 +1,144 @@
/* eslint-disable import/no-duplicates */
/* eslint-disable import/first */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-type-alias */
import {
PropertyType,
} from '../../js/core';
/* eslint-disable @typescript-eslint/consistent-type-definitions */
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable no-inner-declarations */

import {
assertType,
toAssertion,
} from './consts';

type ComplexType = {
a: {
b?: number | {
c: boolean;
};
import { Scalar } from '../../js/core';

{
interface TestInterface { i: any }
class TestClass { c: any; }
type TestType = { t: any };
function testFunction() {}

const scalar1: String extends Scalar ? true : false = true;
const scalar2: string extends Scalar ? true : false = true;
const scalar3: number extends Scalar ? true : false = true;
const scalar4: Number extends Scalar ? true : false = true;
const scalar5: bigint extends Scalar ? true : false = true;
const scalar6: BigInteger extends Scalar ? true : false = true;
const scalar7: Date extends Scalar ? true : false = true;
const scalar8: boolean extends Scalar ? true : false = true;
const scalar9: Boolean extends Scalar ? true : false = true;
const scalar10: null extends Scalar ? true : false = true;
const scalar11: undefined extends Scalar ? true : false = true;
const scalar12: Symbol extends Scalar ? true : false = true;
const scalar13: [] extends Scalar ? true : false = true;
const scalar14: (() => {}) extends Scalar ? true : false = true;
const scalar15: typeof testFunction extends Scalar ? true : false = true;
const scalar16: Symbol extends Scalar ? true : false = true;

const nonScalar1: TestInterface extends Scalar ? true : false = false;
const nonScalar2: TestClass extends Scalar ? true : false = false;
const nonScalar3: TestType extends Scalar ? true : false = false;
const nonScalar4: object extends Scalar ? true : false = false;
}

import { PropertyType } from '../../js/core';

{
type ComplexType = {
a: {
b?: number | {
c: boolean;
};
x: number;
} | { e: string };
}
| string
| {
d: boolean | string;
f: string | {
g: number | Record<number, boolean>;
}[];
};

type AExpected = {
b?: BExpected;
x: number;
} | { e: string };
type BExpected = number | { c: boolean };
type FExpected = string | { g: GExpected }[];
type GExpected = number | Record<number, boolean>;

const a1: AExpected = {
e: 'e',
};
const a2: AExpected = {
x: 42,
};
const a3: AExpected = {
x: 42,
b: 1,
};
const a4: AExpected = {
x: 42,
b: {
c: false,
},
};

assertType<AExpected>(toAssertion(a1));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a1));
assertType<AExpected>(toAssertion(a2));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a2));
assertType<AExpected>(toAssertion(a3));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a3));
assertType<AExpected>(toAssertion(a4));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a4));

const b1: BExpected = 42;
const b2: BExpected = { c: false };
assertType<BExpected>(toAssertion(b1));
assertType<PropertyType<ComplexType, 'a.b'>>(toAssertion(b1));
assertType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>>(toAssertion(b1));
assertType<BExpected>(toAssertion(b2));
assertType<PropertyType<ComplexType, 'a.b'>>(toAssertion(b2));
assertType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>>(toAssertion(b2));

assertType<boolean>(toAssertion(false));
assertType<PropertyType<ComplexType, 'a.b.c'>>(toAssertion(false));
assertType < PropertyType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>, 'c'>>(toAssertion(false));
assertType<boolean>(toAssertion(true));
assertType<PropertyType<ComplexType, 'a.b.c'>>(toAssertion(true));
assertType < PropertyType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>, 'c'>>(toAssertion(true));

assertType<boolean | string>(toAssertion(true));
assertType<PropertyType<ComplexType, 'd'>>(toAssertion(true));
assertType<boolean | string>(toAssertion(false));
assertType<PropertyType<ComplexType, 'd'>>(toAssertion(false));
assertType<boolean | string>(toAssertion('some string'));
assertType<PropertyType<ComplexType, 'd'>>(toAssertion('some string'));

assertType<string>(toAssertion('some string'));
assertType<PropertyType<ComplexType, 'a.e'>>(toAssertion('some string'));
assertType<PropertyType<PropertyType<ComplexType, 'a'>, 'e'>>(toAssertion('some string'));

const f1: FExpected = 'some string';
const f2: FExpected = [{ g: 42 }];
const f3: FExpected = [{ g: { 1: false, 2: false, 3: true } }];

assertType<FExpected>(toAssertion(f1));
assertType<PropertyType<ComplexType, 'f'>>(toAssertion(f1));
assertType<FExpected>(toAssertion(f2));
assertType<PropertyType<ComplexType, 'f'>>(toAssertion(f2));
assertType<FExpected>(toAssertion(f3));
assertType<PropertyType<ComplexType, 'f'>>(toAssertion(f3));

const g1: GExpected = 42;
const g2: GExpected = { 1: false, 2: false, 3: true };
assertType<GExpected>(toAssertion(g1));
assertType<PropertyType<ComplexType, 'f.g'>>(toAssertion(g1));
assertType<PropertyType<PropertyType<ComplexType, 'f'>, 'g'>>(toAssertion(g1));
assertType<GExpected>(toAssertion(g2));
assertType<PropertyType<ComplexType, 'f.g'>>(toAssertion(g2));
assertType<PropertyType<PropertyType<ComplexType, 'f'>, 'g'>>(toAssertion(g2));
}
| string
| {
d: boolean | string;
f: string | {
g: number | Record<number, boolean>;
}[];
};

type AExpected = {
b?: BExpected;
x: number;
} | { e: string };
type BExpected = number | { c: boolean };
type FExpected = string | { g: GExpected }[];
type GExpected = number | Record<number, boolean>;

const a1: AExpected = {
e: 'e',
};
const a2: AExpected = {
x: 42,
};
const a3: AExpected = {
x: 42,
b: 1,
};
const a4: AExpected = {
x: 42,
b: {
c: false,
},
};

assertType<AExpected>(toAssertion(a1));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a1));
assertType<AExpected>(toAssertion(a2));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a2));
assertType<AExpected>(toAssertion(a3));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a3));
assertType<AExpected>(toAssertion(a4));
assertType<PropertyType<ComplexType, 'a'>>(toAssertion(a4));

const b1: BExpected = 42;
const b2: BExpected = { c: false };
assertType<BExpected>(toAssertion(b1));
assertType<PropertyType<ComplexType, 'a.b'>>(toAssertion(b1));
assertType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>>(toAssertion(b1));
assertType<BExpected>(toAssertion(b2));
assertType<PropertyType<ComplexType, 'a.b'>>(toAssertion(b2));
assertType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>>(toAssertion(b2));

assertType<boolean>(toAssertion(false));
assertType<PropertyType<ComplexType, 'a.b.c'>>(toAssertion(false));
assertType < PropertyType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>, 'c'>>(toAssertion(false));
assertType<boolean>(toAssertion(true));
assertType<PropertyType<ComplexType, 'a.b.c'>>(toAssertion(true));
assertType < PropertyType<PropertyType<PropertyType<ComplexType, 'a'>, 'b'>, 'c'>>(toAssertion(true));

assertType<boolean | string>(toAssertion(true));
assertType<PropertyType<ComplexType, 'd'>>(toAssertion(true));
assertType<boolean | string>(toAssertion(false));
assertType<PropertyType<ComplexType, 'd'>>(toAssertion(false));
assertType<boolean | string>(toAssertion('some string'));
assertType<PropertyType<ComplexType, 'd'>>(toAssertion('some string'));

assertType<string>(toAssertion('some string'));
assertType<PropertyType<ComplexType, 'a.e'>>(toAssertion('some string'));
assertType<PropertyType<PropertyType<ComplexType, 'a'>, 'e'>>(toAssertion('some string'));

const f1: FExpected = 'some string';
const f2: FExpected = [{ g: 42 }];
const f3: FExpected = [{ g: { 1: false, 2: false, 3: true } }];

assertType<FExpected>(toAssertion(f1));
assertType<PropertyType<ComplexType, 'f'>>(toAssertion(f1));
assertType<FExpected>(toAssertion(f2));
assertType<PropertyType<ComplexType, 'f'>>(toAssertion(f2));
assertType<FExpected>(toAssertion(f3));
assertType<PropertyType<ComplexType, 'f'>>(toAssertion(f3));

const g1: GExpected = 42;
const g2: GExpected = { 1: false, 2: false, 3: true };
assertType<GExpected>(toAssertion(g1));
assertType<PropertyType<ComplexType, 'f.g'>>(toAssertion(g1));
assertType<PropertyType<PropertyType<ComplexType, 'f'>, 'g'>>(toAssertion(g1));
assertType<GExpected>(toAssertion(g2));
assertType<PropertyType<ComplexType, 'f.g'>>(toAssertion(g2));
assertType<PropertyType<PropertyType<ComplexType, 'f'>, 'g'>>(toAssertion(g2));
28 changes: 23 additions & 5 deletions ts/dx.all.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1676,11 +1676,11 @@ declare module DevExpress.core {
/**
* @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 object
? {
[P in keyof T]?: T[P] extends Function ? T[P] : DeepPartial<T[P]>;
}
: T;
export type DeepPartial<T> = T extends Scalar
? T
: {
[P in keyof T]?: DeepPartial<T[P]>;
};
export type DefaultOptionsRule<T> = {
device?: Device | Device[] | ((device: Device) => boolean);
options: DeepPartial<T>;
Expand Down Expand Up @@ -1757,6 +1757,24 @@ declare module DevExpress.core {
* @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.
*/
interface PromiseType<T> extends JQueryPromise<T> {}
/**
* @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 Scalar =
| undefined
| null
| string
| String
| number
| Number
| bigint
| BigInteger
| boolean
| Boolean
| Date
| Function
| Symbol
| Array<unknown>;
/**
* [descr:template]
*/
Expand Down

0 comments on commit 0f23421

Please sign in to comment.