Skip to content

Instantly share code, notes, and snippets.

@brombal
Last active December 23, 2021 16:54
Show Gist options
  • Save brombal/6fc10953c0b082bb12444ba7feb24e4b to your computer and use it in GitHub Desktop.
Save brombal/6fc10953c0b082bb12444ba7feb24e4b to your computer and use it in GitHub Desktop.
getComparison - compare two objects using ===
/**
Returns an object that can be used to compare `a` and `b` (and their nested properties) using `===`.
The return value will be structurally the same as `b`. However, any properties that are
equivalent objects (using a deep comparison) to `a`'s properties will be comparable using `===`.
This will be true for properties at any nested level, including the top level (i.e. if `a` and `b`
are equivalent, `a` will be identical to the return value).
E.g.:
```
const a = {
firstName: 'Alex',
favoriteBook: {
title: 'Green Eggs and Ham',
author: 'Dr. Seuss'
},
favoriteSong: {
title: 'Row row row your boat',
composer: 'Unknown'
}
};
const b = {
firstName: 'Alex',
favoriteBook: {
title: 'Green Eggs and Ham',
author: 'Dr. Seuss'
},
favoriteSong: {
title: 'Twinkle twinkle',
composer: 'Mozart'
}
};
const comparison = getComparison(a, b);
a === comparison // false
a.firstName === comparison.firstName // true
a.favoriteBook === comparison.favoriteBook // true
a.favoriteSong === comparison.favoriteSong // false
```
*/
export function getComparison(a: any, b: any): any {
if (a === b) return a;
if (typeof a !== typeof b) return cloneDeep(b);
if (!b || !a) return cloneDeep(b);
if (typeof a === 'object') {
let changed = false;
const result: any = Array.isArray(a) ? [] : {};
for (const key in b) {
const compared = getComparison(a[key], b[key]);
if (compared !== a[key]) {
result[key] = compared;
changed = true;
} else {
result[key] = a[key];
}
}
for (const key in a) {
if (!(key in b)) changed = true;
}
return changed ? result : a;
} else {
return cloneDeep(b);
}
}
/**
* Deeply clones a value.
*/
export function cloneDeep<T>(value: T): T {
if (!value || typeof value !== 'object') return value;
if (Array.isArray(value)) {
const clone: any = [];
for (let index = 0; index < value.length; ++index) {
clone.push(cloneDeep(value[index]));
}
return clone;
}
if (isPlainObject(value)) {
const clone: any = {};
for (const key in value) {
clone[key] = cloneDeep(value[key]);
}
return clone;
}
return value;
}
/**
* Indicates that an object is most likely just an object literal.
*/
export function isPlainObject(obj: any): boolean {
return obj && typeof obj === 'object' && obj.constructor.prototype === Object.prototype;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment