Skip to content

Instantly share code, notes, and snippets.

@soulsam480
Last active April 9, 2022 21:19
Show Gist options
  • Save soulsam480/e65309bc0d01ca0560b4b1dd065681d6 to your computer and use it in GitHub Desktop.
Save soulsam480/e65309bc0d01ca0560b4b1dd065681d6 to your computer and use it in GitHub Desktop.
Deep diff between two objects. has a few deps
export const toString = (val: any) => Object.prototype.toString.call(val)
export type NullToUndefined<T> = T extends null ? undefined : T
/**
* Get deep diff of objects
* @param toMatch base data
* @param newData new data
* @param asNullKeys convert `undefined` to `null`
* @returns diff
*/
export function getDiff<
T extends Record<string, any>,
U extends Array<keyof T> = never[],
V = U extends Array<infer W> ? W : never,
>(
toMatch: T,
newData?: Partial<T>,
asNullKeys: U = [] as unknown as U,
): { [X in keyof T]: X extends V ? T[X] | undefined | null : NullToUndefined<T[X]> | undefined } {
if (newData === undefined || newData === null) return {} as any
function compareValues(a: any, b: any) {
if (typeof a === 'boolean' || typeof b === 'boolean') return a === b
if (dayjs(a).isValid() || dayjs(b).isValid()) {
// check for dates
return formatDate(a, 'DD/MM/YYYY') === formatDate(b, 'DD/MM/YYYY')
}
return a === b
}
const result: any = {}
Object.keys(toMatch).forEach((key: keyof T) => {
const value = toMatch[key]
const newValue = newData[key]
if (Array.isArray(value) && Array.isArray(newValue)) {
// skip arrays and send new
result[key] = newValue
}
if (toString(value) === '[object Object]') {
// deep object check
const odiff = getDiff(value, newValue)
if (Object.keys(odiff).length > 0) {
result[key] = odiff as any
return
}
}
if (compareValues(newValue, value) || newValue === '') return
if (newValue === undefined && asNullKeys.includes(key)) {
result[key] = null
return
}
result[key] = newValue
})
return result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment