Here is a modern implementation that accounts for Set
and Map
too:
export function deepClone<T extends object>(value: T): T {
if (typeof value !== 'object' || value === null) {
return value;
}
if (value instanceof Set) {
return new Set(Array.from(value, deepClone)) as T;
}
if (value instanceof Map) {
return new Map(Array.from(value, ([k, v]) => [k, deepClone(v)])) as T;
}
if (value instanceof Date) {
return new Date(value) as T;
}
if (value instanceof RegExp) {
return new RegExp(value.source, value.flags) as T;
}
return Object.keys(value).reduce((acc, key) => {
return Object.assign(acc, { [key]: deepClone(value[key]) });
}, (Array.isArray(value) ? [] : {}) as T);
}
Trying it out:
deepClone({
test1: { '1': 1, '2': {}, '3': [1, 2, 3] },
test2: [1, 2, 3],
test3: new Set([1, 2, [1, 2, 3]]),
test4: new Map([['1', 1], ['2', 2], ['3', 3]])
});
test1:
1: 1
2: {}
3: [1, 2, 3]
test2: Array(3)
0: 1
1: 2
2: 3
test3: Set(3)
0: 1
1: 2
2: [1, 2, 3]
test4: Map(3)
0: {"1" => 1}
1: {"2" => 2}
2: {"3" => 3}