forked from InteractiveAdvertisingBureau/iabtcf-es
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCloneable.ts
More file actions
111 lines (70 loc) · 2.27 KB
/
Cloneable.ts
File metadata and controls
111 lines (70 loc) · 2.27 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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* Abstract Class Cloneable<T> can be extended to give the child class the ability to clone its self.
* The child class must pass its class to super. You can then pass any needed arguments to help build
* the cloned class to the protected _clone() method.
*
* Example:
*
* class Example extends Cloneable<Example> {
*
* }
* Todo: There must be more non primitive build in types to check. But for our current purposes, this works great.
*/
export abstract class Cloneable<T> {
/**
* clone - returns a copy of the classes with new values and not references
*
* @return {T}
*/
public clone(): T {
const myClone = new (this.constructor as {new(): T})();
const keys = Object.keys(this);
keys.forEach((key: string): void => {
const value: unknown = this.deepClone(this[key]);
if (value !== undefined) {
myClone[key] = value;
}
});
return myClone;
};
/**
* deepClone - recursive function that makes copies of reference values
*
* @param {unknown} item
* @return {unknown}
*/
private deepClone(item: unknown): unknown {
const itsType = typeof item;
if (itsType === 'number' || itsType === 'string' || itsType === 'boolean') {
return item;
} else if (item !== null && itsType === 'object') {
if (typeof (item as Cloneable<unknown>).clone === 'function') {
return (item as Cloneable<unknown>).clone();
} else if (item instanceof Date) {
return new Date(item.getTime());
} else if ((item as Iterable<unknown>)[Symbol.iterator] !== undefined) {
const ar: unknown[] = [];
for (const subItem of item as Iterable<unknown>) {
ar.push(this.deepClone(subItem));
}
if (item instanceof Array) {
return ar;
} else {
return new ((item as Iterable<unknown>).constructor as {new(ar: unknown[])})(ar);
}
} else {
const retr = {};
for (const prop in item as object) {
if ((item as object).hasOwnProperty(prop)) {
retr[prop] = this.deepClone((item as object)[prop]);
}
}
return retr;
}
}
/**
* ignore functions because those will be initialized with the cloning
* process
*/
}
}