|
| 1 | +/* |
| 2 | + Deep clones all properties except functions |
| 3 | +
|
| 4 | + var arr = [1, 2, 3]; |
| 5 | + var subObj = {aa: 1}; |
| 6 | + var obj = {a: 3, b: 5, c: arr, d: subObj}; |
| 7 | + var objClone = clone(obj); |
| 8 | + arr.push(4); |
| 9 | + subObj.bb = 2; |
| 10 | + obj; // {a: 3, b: 5, c: [1, 2, 3, 4], d: {aa: 1}} |
| 11 | + objClone; // {a: 3, b: 5, c: [1, 2, 3], d: {aa: 1, bb: 2}} |
| 12 | +*/ |
| 13 | + |
| 14 | +export function clone<T>(obj: T): T { |
| 15 | + const type = {}.toString.call(obj).slice(8, -1); |
| 16 | + if (type == 'Set') { |
| 17 | + // @ts-expect-error Known type |
| 18 | + return new Set([...obj].map((value) => clone(value))); |
| 19 | + } |
| 20 | + if (type == 'Map') { |
| 21 | + // @ts-expect-error Known type |
| 22 | + return new Map([...obj].map((kv) => [clone(kv[0]), clone(kv[1])])); |
| 23 | + } |
| 24 | + if (type == 'Date') { |
| 25 | + // @ts-expect-error Known type |
| 26 | + return new Date(obj.getTime()); |
| 27 | + } |
| 28 | + if (type == 'RegExp') { |
| 29 | + // @ts-expect-error Known type |
| 30 | + return RegExp(obj.source, (obj as RegExp).flags); |
| 31 | + } |
| 32 | + if (type == 'Array') { |
| 33 | + // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 34 | + const result = [] as any; |
| 35 | + for (const key in obj) { |
| 36 | + result[key] = clone(obj[key]); |
| 37 | + } |
| 38 | + return result; |
| 39 | + } |
| 40 | + if (type == 'Object') { |
| 41 | + return Object.assign(Object.create(Object.getPrototypeOf(obj)), obj); |
| 42 | + } |
| 43 | + |
| 44 | + // primitives and non-supported objects (e.g. functions) land here |
| 45 | + return obj; |
| 46 | +} |
0 commit comments