Skip to content

Instantly share code, notes, and snippets.

@frydlewicz
Last active July 26, 2020 08:14
Show Gist options
  • Save frydlewicz/0c7ed3f08c4cd4b5762f7d8ecf3227ec to your computer and use it in GitHub Desktop.
Save frydlewicz/0c7ed3f08c4cd4b5762f7d8ecf3227ec to your computer and use it in GitHub Desktop.
TypeScript methods cloning and comparing objects using WeakMap and WeakSet
export interface IObject {
[key: string]: any;
}
export function cloneObject(source: IObject, maxDeep: number = Infinity): IObject {
if (typeof source !== 'object') {
throw new Error('Argument must be an object');
}
const refs = new WeakMap<IObject, IObject>();
const dest: IObject = {};
(function deepSearch(dest: IObject, source: IObject, deep: number = 0): void {
for (const key of Object.keys(source)) {
const node = source[key];
if (node.constructor === Date) {
dest[key] = new Date(node);
} else if (typeof node !== 'object' || deep >= maxDeep ||
node.constructor !== Array && node.constructor !== Object) {
dest[key] = node;
} else {
const ref = refs.get(node);
if (ref) {
dest[key] = ref;
} else {
if (node.constructor === Array) {
dest[key] = [];
} else {
dest[key] = {};
}
refs.set(node, dest[key]);
deepSearch(dest[key], node, deep + 1);
}
}
}
})(dest, source);
return dest;
}
export function sameObjects(obj1: IObject, obj2: IObject = {}): boolean {
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') {
throw new Error('Arguments must be objects');
}
const refs = new WeakSet<IObject>();
return (function deepSearch(obj1: IObject, obj2: IObject): boolean {
for (const key of Object.keys(obj1)) {
const type1 = typeof obj1[key];
const type2 = typeof obj2[key];
if (type2 === 'undefined' || type1 !== type2) {
return false;
} else if (type1 === 'object') {
if (!refs.has(obj1[key])) {
refs.add(obj1[key]);
if (obj1[key].toString() !== obj2[key].toString() ||
!deepSearch(obj1[key], obj2[key])) {
return false;
}
}
} else if (type1 === 'function') {
if (obj1[key].toString() !== obj2[key].toString()) {
return false;
}
} else if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
})(obj1, obj2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment