@magic/types
Version:
typechecking library
109 lines (87 loc) • 2.15 kB
JavaScript
// Written by Substack <3
import is from '../lib.mjs'
export const equal = (a, b) => {
// curry
if (is.undefined(b)) {
if (is.undefined(a)) {
// this is not true, but it has to be assumed this is an unintentional comparation
return false
}
return c => equal(a, c)
}
if (is.null(b)) {
return a === b
}
// types must match
if (typeof a !== typeof b) {
return false
}
// bool, string, number, falsy values
if (is.comparable(a) || is.comparable(b)) {
return a === b
}
// if (is.<arguments(a)) {
// return is.length.eq(a, b)
// }
// identical 'prototype' property.
if (a.prototype !== b.prototype) {
return false
}
// real types must match too
if (Object.prototype.toString.call(a) !== Object.prototype.toString.call(b)) {
return false
}
// dates
if (is.date(a)) {
return a === b
}
// functions
if (is.function(a)) {
return a.toString() === b.toString()
}
// buffers
if (is.buffer(a)) {
if (a.length !== b.length) {
return false
}
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false
}
}
return true
}
// objects
const ka = Object.keys(a)
const kb = Object.keys(b)
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length !== kb.length) {
return false
}
// the same set of keys (although not necessarily the same order),
ka.sort()
kb.sort()
// ~~~cheap key test
for (let i = ka.length - 1; i >= 0; i--) {
if (ka[i] !== kb[i]) {
return false
}
}
// equivalent values for every corresponding key, and
// ~~~possibly expensive deep test
let key
for (let i = ka.length - 1; i >= 0; i--) {
key = ka[i]
// in the first line of this function we assume that two undefined values are a bug.
// here we have to assume that two undefined properties in an object are intentional.
if (is.undefined(a[key])) {
return a[key] === b[key]
}
if (!equal(a[key], b[key])) {
return false
}
}
return typeof a === typeof b
}
export default equal