-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdeep-clone.ts
More file actions
65 lines (55 loc) · 1.97 KB
/
Copy pathdeep-clone.ts
File metadata and controls
65 lines (55 loc) · 1.97 KB
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
59
60
61
62
63
64
65
// TS does not allow for circular types, but there is a trick with interfaces:
// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540
// eslint-disable-next-line no-use-before-define
type DeepCloneSupportedType = boolean | number | bigint | string | undefined | null | Date | IDeepCloneSupportedTypeObject | IDeepCloneSupportedTypeArray;
interface IDeepCloneSupportedTypeObject {
[x: string]: DeepCloneSupportedType;
}
// the part of the trick above
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IDeepCloneSupportedTypeArray extends Array<DeepCloneSupportedType> { }
/**
* WARNING!
*
* There is a problem with __proto__ support in TypeScript. Since our tests are written in TypeScript,
* we don't test this helper. Please be careful when changing this function!
*
* @deprecated since v8.9.0 - use structuredClone instead
* @see https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
*/
function deepClone<T extends DeepCloneSupportedType>(obj: T): T;
function deepClone(obj: DeepCloneSupportedType): DeepCloneSupportedType {
if (obj == null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
const copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
if (obj instanceof Array) {
const copy: IDeepCloneSupportedTypeArray = [];
for (let i = 0, len = obj.length; i < len; i++) {
copy[i] = deepClone(obj[i]);
}
return copy;
}
const copy: typeof obj = {};
Object.keys(obj).forEach(key => {
const value = deepClone(obj[key]);
// The __proto__ property has a special meaning in JavaScript. So, to prevent prototype poisoning,
// we restrict direct assignment to this property.
if (key === '__proto__') {
Object.defineProperty(copy, key, {
configurable: true,
enumerable: true,
value,
writable: true,
});
} else {
copy[key] = value;
}
});
return copy;
}
export default deepClone;