mauss
Version:
practical functions and reusable configurations
49 lines (48 loc) • 1.96 kB
JavaScript
/**
* A function to check for value equality between two variables. This will work for any data type except `function`, which will always return `true` when two function are being compared. The heuristics are as follows:
* - fails immediately when the type of `x` and `y` are not the same
* - type of `function` are not comparable, always returns true
* - type of `symbol` is converted and compared as a `string`
* - primitive values are compared using strict equality operator
* - type of `object`, two empty array or object are considered the same
* - type of `object`, comparing array also considers its length and item order
* - type of `object`, two object must have the same keys before comparing its values
* - type of `object`, the order of key-value pair does not matter for equality check
* - `identical` is infinitely recursive for any amount of nested array/object
*/
export function identical(x, y) {
const [xt, yt] = [typeof x, typeof y];
if (xt !== yt)
return false;
if (xt === 'function')
return true;
if (xt === 'symbol') {
// @ts-expect-error - guaranteed symbol
return x.toString() === y.toString();
}
if (xt !== 'object')
return x === y;
if (x == null || y == null)
return x === y;
if (Array.isArray(x) !== Array.isArray(y))
return false;
if (Array.isArray(x) && Array.isArray(y)) {
if (x.length !== y.length)
return false;
for (let i = 0; i < x.length; i++) {
if (!identical(x[i], y[i]))
return false;
}
return true;
}
const [xk, yk] = [Object.keys(x), Object.keys(y)];
const keys = new Set([...xk, ...yk]);
if (xk.length !== yk.length || keys.size !== xk.length)
return false;
for (const k of keys) {
// @ts-expect-error - guaranteed indexable
if (!identical(x[k], y[k]))
return false;
}
return true;
}