Skip to content

Instantly share code, notes, and snippets.

@Aleksey-Danchin
Created December 24, 2022 11:21
Show Gist options
  • Save Aleksey-Danchin/cd213130b302812cdbb4a321e000333d to your computer and use it in GitHub Desktop.
Save Aleksey-Danchin/cd213130b302812cdbb4a321e000333d to your computer and use it in GitHub Desktop.
const getType = (x: any) => Object.prototype.toString.call(x).slice(8, -1);
// prettier-ignore
const primitiveTypes = ["Number", "String", "Boolean", "Null", "BigInt", 'Symbol', 'Undefined'];
const isPrimitiveType = (x: any) => primitiveTypes.includes(getType(x));
export const getCopy = (x: any) => {
if (isPrimitiveType(x)) {
return x;
}
const bank = new WeakMap();
const getScoppedCopy = (x: any) => {
if (isPrimitiveType(x)) {
return x;
}
if (Array.isArray(x)) {
if (!bank.has(x)) {
const array = [];
for (const item of x) {
array.push(getScoppedCopy(item));
}
bank.set(x, array);
}
return bank.get(x);
}
const type = getType(x);
if (type === "Map") {
if (!bank.has(x)) {
const map = new Map();
for (const [key, value] of x.entries()) {
map.set(key, getCopy(value));
}
bank.set(x, map);
}
return bank.get(x);
}
if (type === "Set") {
if (!bank.has(x)) {
const set = new Set();
for (const value of x.values()) {
set.add(getCopy(value));
}
bank.set(x, set);
}
return bank.get(x);
}
if (type === "Object") {
if (!bank.has(x)) {
const obj = {} as { [key: string]: any };
for (const [key, value] of Object.entries(x)) {
obj[key] = getScoppedCopy(value);
}
bank.set(x, obj);
}
return bank.get(x);
}
const proto = Object.getPrototypeOf(x);
if (proto && proto?.constructor) {
if (!bank.has(x)) {
bank.set(x, new proto.constructor(x));
}
return bank.get(x);
}
throw new Error(`Unkown type "${type}"`);
};
return getScoppedCopy(x);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment