diff --git a/types/index.d.ts b/types/index.d.ts index 5b42043..b7fedcc 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -8,7 +8,7 @@ type DeepMergeAll< Ts extends readonly [any, ...any[]], Options extends deepmerge.Options > = Ts extends readonly [infer T1, ...any[]] - ? Ts extends readonly [any, infer T2, ...infer TRest] + ? Ts extends readonly [T1, infer T2, ...infer TRest] ? TRest extends readonly never[] ? DeepMerge : DeepMerge, Options> @@ -23,52 +23,40 @@ type DeepMerge = IsSame< T2 > extends true ? T1 | T2 - : IsObjectOrArray extends true - ? IsObjectOrArray extends true - ? DeepMergeNonPrimitive - : MergeLeafs - : MergeLeafs; + : And, IsObjectOrArray> extends true + ? DeepMergeNonPrimitive + : Leaf; /** * Deep merge 2 objects (they may be arrays). */ -type DeepMergeNonPrimitive< - T1, - T2, - Options extends deepmerge.Options -> = ShouldMergeArrays extends true +type DeepMergeNonPrimitive = And< + IsArray, + IsArray +> extends true ? DeepMergeArrays - : DeepMergeObjects; - -/** - * Deep merge 2 non-array types. - */ -type DeepMergeObjects< - T1, - T2, - Options extends deepmerge.Options -> = ShouldMergeObjects extends true - ? DeepMergeObjectProps - : MergeLeafs; + : And, IsObject> extends true + ? DeepMergeObjects + : Leaf; /** * Deep merge 2 non-array objects. */ -type DeepMergeObjectProps< +type DeepMergeObjects< T1, T2, Options extends deepmerge.Options > = FlatternAlias< // @see https://github.com/microsoft/TypeScript/issues/41448 { - -readonly [K in keyof T1]: DeepMergeProps< + -readonly [K in keyof T1]: DeepMergeObjectProps< ValueOfKey, ValueOfKey, Options >; } & { - -readonly [K in keyof T2]: DeepMergeProps< + -readonly [K in keyof T2]: DeepMergeObjectProps< ValueOfKey, ValueOfKey, Options @@ -80,32 +68,32 @@ type DeepMergeObjectProps< * Deep merge 2 types that are known to be properties of an object being deeply * merged. */ -type DeepMergeProps = GetOption< - Options, - "isMergeableObject" -> extends undefined +type DeepMergeObjectProps = Or< + IsUndefinedOrNever, + IsUndefinedOrNever +> extends true + ? Leaf + : GetOption extends undefined ? GetOption extends undefined ? DeepMerge - : DeepMergePropsCustom - : MergeMaybeLeafs; + : DeepMergeObjectPropsCustom + : MaybeLeaf; /** * Deep merge 2 types that are known to be properties of an object being deeply * merged and where a "customMerge" function has been provided. */ -type DeepMergePropsCustom< +type DeepMergeObjectPropsCustom< T1, T2, Options extends deepmerge.Options > = ReturnType>> extends undefined ? DeepMerge : undefined extends ReturnType>> - ? IsArray extends true - ? IsArray extends true + ? Or, IsArray> extends true + ? And, IsArray> extends true ? DeepMergeArrays - : MergeLeafs - : IsArray extends true - ? MergeLeafs + : Leaf : | DeepMerge | ReturnType< @@ -133,34 +121,25 @@ type DeepMergeArrays< : never; /** - * Get the leaf type of 2 types that can't be merged. + * Get the leaf type from 2 types that can't be merged. */ -type MergeLeafs = Is extends true +type Leaf = IsNever extends true ? T1 - : Is extends true + : IsNever extends true ? T2 - : Is extends true + : IsUndefinedOrNever extends true ? T1 : T2; /** - * Get the leaf type of 2 types that might not be able to be merged. + * Get the leaf type from 2 types that might not be able to be merged. */ -type MergeMaybeLeafs = Is< - T2, - never +type MaybeLeaf = Or< + Or, IsUndefinedOrNever>, + Not, IsObjectOrArray>> > extends true - ? T1 - : Is extends true - ? T2 - : Is extends true - ? T1 - : Is extends true - ? T2 - : Is extends false - ? DeepMerge - : Is extends false - ? DeepMerge + ? Leaf + // TODO: Handle case where return type of "isMergeableObject" is a typeguard. If it is we can do better than just "unknown". : unknown; /** @@ -181,6 +160,16 @@ type ValueOfKey = K extends keyof T ? T[K] : never; */ type Is = [T1] extends [T2] ? true : false; +/** + * Safely test whether or not the given type is "never". + */ +type IsNever = Is; + +/** + * Is the given type undefined or never? + */ +type IsUndefinedOrNever = Is; + /** * Returns whether or not the give two types are the same. */ @@ -189,33 +178,37 @@ type IsSame = Is extends true ? Is : false; /** * Returns whether or not the given type an object (arrays are objects). */ -type IsObjectOrArray = Is extends true ? false : Is; +type IsObjectOrArray = And>, T extends object ? true : false>; /** * Returns whether or not the given type a non-array object. */ -type IsObject = IsArray extends true - ? false - : IsObjectOrArray; +type IsObject = And, Not>>; /** * Returns whether or not the given type an array. */ -type IsArray = Is>; +type IsArray = And< + Not>, + T extends ReadonlyArray ? true : false +>; + +/** + * And operator for types. + */ +type And = T1 extends false + ? false + : T2; /** - * Returns whether or not 2 types are both non-array objects that can be merged. + * Or operator for types. */ -type ShouldMergeObjects = IsObject extends true - ? IsObject - : false; +type Or = T1 extends true ? true : T2; /** - * Returns whether or not 2 types are both arrays that can be merged. + * Not operator for types. */ -type ShouldMergeArrays = IsArray extends true - ? IsArray - : false; +type Not = T extends true ? false : true; /** * A function that merges any 2 arrays.