-
Notifications
You must be signed in to change notification settings - Fork 1
/
merge.ts
58 lines (55 loc) · 1.58 KB
/
merge.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* Please refer to the terms of the license agreement in the root of the project
*
* (c) 2024 Feedzai
*/
import { ObjTypeWithAny } from "src/typings";
/**
* This method is like `assign` except that it recursively merges own and
* inherited enumerable string keyed properties of source objects into the
* destination object.
*
* Source properties that resolve to `undefined` are
* skipped if a destination value exists.
*
* Array and plain object properties are merged recursively.
*
* Other objects and value types are overridden by
* assignment.
*
* Source objects are applied from left to right.
*
* Subsequent sources overwrite property assignments of previous sources.
*
* **Note:** This method mutates `object`.
*
* @example
*
* const object = {
* 'a': [{ 'b': 2 }, { 'd': 4 }]
* }
*
* const other = {
* 'a': [{ 'c': 3 }, { 'e': 5 }]
* }
*
* merge(object, other)
* // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
*/
export function merge<T extends ObjTypeWithAny, U extends ObjTypeWithAny>(
target: T,
source: U
): T & U {
const merged: any = { ...target };
for (const key in source) {
if (typeof source[key] === "object" && source[key] !== null && !Array.isArray(source[key])) {
merged[key] = merge(target[key] ?? {}, source[key]);
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
// Merge arrays recursively @ts-ignore
merged[key] = target[key].map((item: any, index: number) => merge(item, source[key][index]));
} else {
merged[key] = source[key];
}
}
return merged as T & U;
}