Created
January 15, 2021 16:14
-
-
Save vbfox/2cf6dc6833aa3fcf3483012731268c5a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-unsafe-return */ | |
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ | |
function deepReferentialEquality(from: any, to: any, path = ''): any { | |
if (to === undefined || from === undefined || to === null || from === null) { | |
return to; | |
} | |
const objectType = typeof from; | |
if (objectType !== typeof to) { | |
// The object changed type | |
return to; | |
} | |
if (from === to) { | |
// Same type so either it's the same object reference or the same primitive value | |
return from; | |
} | |
function isPlainObject(o: any) { | |
return Object.prototype.isPrototypeOf.call(Object.getPrototypeOf(o), Object); | |
} | |
if (objectType === 'object') { | |
if (isPlainObject(to) && isPlainObject(from)) { | |
let canReturnFrom = true; | |
let canReturnTo = true; | |
const toKeys = Object.keys(to); | |
const result: any = {}; | |
for (const key of toKeys) { | |
const finalValue = deepReferentialEquality(from[key], to[key], `${path}.${key}`); | |
result[key] = finalValue; | |
if (finalValue !== to) { | |
canReturnTo = false; | |
} | |
if (finalValue !== from) { | |
canReturnFrom = false; | |
} | |
} | |
if (canReturnTo) { | |
return to; | |
} | |
if (canReturnFrom) { | |
// Assume from has no extra keys or we don't care | |
return from; | |
} | |
return result; | |
} | |
if (Array.isArray(to) && Array.isArray(from)) { | |
let canReturnFrom = to.length === from.length; | |
let canReturnTo = true; | |
const result: any[] = []; | |
// eslint-disable-next-line | |
for (const i in to) { | |
const finalValue: any = deepReferentialEquality(from[i], to[i], `${path}[${i}]`); | |
result[i] = finalValue; | |
if (finalValue !== to) { | |
canReturnTo = false; | |
} | |
if (finalValue !== from) { | |
canReturnFrom = false; | |
} | |
} | |
if (canReturnTo) { | |
return to; | |
} | |
if (canReturnFrom) { | |
return from; | |
} | |
return result; | |
} | |
} | |
// We don't optimize that type | |
return to; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment