diff --git a/index.d.ts b/index.d.ts index e848bff..4b62032 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,9 +1,37 @@ -export function diff (originalObj: object, updatedObj: object): object +type DeepPartial = { + [K in keyof T]?: DeepPartial +} -export function addedDiff (originalObj: object, updatedObj: object): object +interface IDictionary { + [key: string]: T; +} -export function deletedDiff (originalObj: object, updatedObj: object): object +/* + In "deep-object-diff" there're 2 scenarios for a property diff: + 1. If the property is an object or primitive, the diff is a deep partial; + 2. If the property is an array, the diff is a dictionary. + Its keys are indices, and the values are deep partials of the change. +*/ +type PropertyDiff = T extends Array + ? IDictionary + : DeepPartial; -export function updatedDiff (originalObj: object, updatedObj: object): object +export type Diff = { + [P in keyof T]?: PropertyDiff; +}; -export function detailedDiff (originalObj: object, updatedObj: object): object +export interface IDetailedDiff { + added: Diff; + deleted: Diff; + updated: Diff; +} + +export function diff (originalObj: T, updatedObj: T): Diff + +export function addedDiff (originalObj: T, updatedObj: T): Diff + +export function deletedDiff (originalObj: T, updatedObj: T): Diff + +export function updatedDiff (originalObj: T, updatedObj: T): Diff + +export function detailedDiff (originalObj: T, updatedObj: T): IDetailedDiff diff --git a/src/diff/index.js b/src/diff/index.js index 74b961b..ee29b00 100644 --- a/src/diff/index.js +++ b/src/diff/index.js @@ -3,6 +3,10 @@ import { isDate, isEmpty, isObject, properObject } from '../utils'; const diff = (lhs, rhs) => { if (lhs === rhs) return {}; // equal return no diff + if (typeof lhs === "number" && typeof rhs === "number") { + if (isNaN(lhs) && isNaN(rhs)) return {}; // NaN is equal + } + if (!isObject(lhs) || !isObject(rhs)) return rhs; // return updated rhs const l = properObject(lhs); diff --git a/src/diff/index.test.js b/src/diff/index.test.js index 32ba35f..11dcde7 100644 --- a/src/diff/index.test.js +++ b/src/diff/index.test.js @@ -13,6 +13,7 @@ describe('.diff', () => { ['object', { a: 1 }], ['array', [1]], ['function', () => ({})], + ['NaN', NaN], ['date', new Date()], ['date with milliseconds', new Date('2017-01-01T00:00:00.637Z')], ])('returns empty object when given values of type %s are equal', (type, value) => { @@ -56,7 +57,7 @@ describe('.diff', () => { }); test('returns subset of right hand side value when nested values differ', () => { - expect(diff({ a: { b: 1, c: 2} }, { a: { b: 1, c: 3 } })).toEqual({ a: { c: 3 } }); + expect(diff({ a: { b: 1, c: 2 } }, { a: { b: 1, c: 3 } })).toEqual({ a: { c: 3 } }); }); test('returns subset of right hand side value when nested values differ at multiple paths', () => { @@ -72,7 +73,7 @@ describe('.diff', () => { }); test('returns keys as undefined when deleted from right hand side', () => { - expect(diff({ a: 1, b: { c: 2 }}, { a: 1 })).toEqual({ b: undefined }); + expect(diff({ a: 1, b: { c: 2 } }, { a: 1 })).toEqual({ b: undefined }); }); }); @@ -139,7 +140,7 @@ describe('.diff', () => { test('returns subset of right hand side value when nested values differ', () => { const lhs = Object.create(null); - lhs.a = { b: 1, c: 2}; + lhs.a = { b: 1, c: 2 }; const rhs = Object.create(null); rhs.a = { b: 1, c: 3 }; expect(diff(lhs, rhs)).toEqual({ a: { c: 3 } }); @@ -173,5 +174,15 @@ describe('.diff', () => { expect(diff(lhs, rhs)).toEqual({ b: 2 }); }); }); + + describe('nested NaN', () => { + test('returns empty object when there is nested NaN value', () => { + expect(diff({ a: 1, b: NaN }, { a: 1, b: NaN })).toEqual({}); + }); + + test('returns subset of right hand side when a left hand side value is not a NaN', () => { + expect(diff({ a: 1, b: 2 }, { a: 1, b: NaN })).toEqual({ b: NaN }); + }); + }); }); });