@fastify/deepmerge
Version:
Merges the enumerable properties of two or more objects deeply.
92 lines (74 loc) • 2.48 kB
TypeScript
type DeepMergeFn = <T1, T2>(target: T1, source: T2) => DeepMerge<T1, T2>
type DeepMergeAllFn = <T extends Array<any>>(...targets: T) => DeepMergeAll<{}, T>
type Primitive =
| null
| undefined
| string
| number
| boolean
| symbol
| bigint
type BuiltIns = Primitive | Date | RegExp
type MergeArrays<T, U> = T extends readonly any[]
? U extends readonly any[]
? [...T, ...U]
: never
: never
type DifferenceKeys<
T,
U,
T0 = Omit<T, keyof U> & Omit<U, keyof T>,
T1 = { [K in keyof T0]: T0[K] }
> = T1
type IntersectionKeys<T, U> = Omit<T | U, keyof DifferenceKeys<T, U>>
type DeepMergeHelper<
T,
U,
T0 = DifferenceKeys<T, U>
& { [K in keyof IntersectionKeys<T, U>]: DeepMerge<T[K], U[K]> },
T1 = { [K in keyof T0]: T0[K] }
> = T1
type DeepMerge<T, U> =
U extends BuiltIns
? U
: [T, U] extends [readonly any[], readonly any[]]
? MergeArrays<T, U>
: [T, U] extends [{ [key: string]: unknown }, { [key: string]: unknown }]
? DeepMergeHelper<T, U>
: U
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type First<T> = T extends [infer _I, ...infer _Rest] ? _I : never
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type Rest<T> = T extends [infer _I, ...infer _Rest] ? _Rest : never
type DeepMergeAll<R, T> = First<T> extends never
? R
: DeepMergeAll<DeepMerge<R, First<T>>, Rest<T>>
type MergeArrayFnOptions = {
clone: (value: any) => any;
isMergeableObject: (value: any) => boolean;
deepmerge: DeepMergeFn;
getKeys: (value: object) => string[];
}
/**
* A function responsible handling the cloning logic of the provided prototype object.
*
* @param value - The proto object to clone.
* @returns the resulting clone (can also return the object itself if you do not want clone but replace).
*/
type CloneProtoObjectFn = (value: any) => any
type MergeArrayFn = (options: MergeArrayFnOptions) => (target: any[], source: any[]) => any[]
interface Options {
cloneProtoObject?: CloneProtoObjectFn;
mergeArray?: MergeArrayFn;
symbols?: boolean;
all?: boolean;
}
type DeepmergeConstructor = typeof deepmerge
declare namespace deepmerge {
export { Options, DeepMergeFn, DeepMergeAllFn }
export const deepmerge: DeepmergeConstructor
export { deepmerge as default }
}
declare function deepmerge (options: Options & { all: true }): DeepMergeAllFn
declare function deepmerge (options?: Options): DeepMergeFn
export = deepmerge