export function isEmpty ( obj ) { return Object . keys ( obj ) . length === 0 ; } export interface DeepEqualsOptions { treatUndefinedAndMissingKeyAsSame ? : boolean ; } const defaultOptions = { treatUndefinedAndMissingKeyAsSame : false , } ; export function deepEquals < T > ( _1 , _2 , options = { } ) { const { treatUndefinedAndMissingKeyAsSame } = Object . assign ( { } , defaultOptions , options ) ; const leftChain = [ ] ; const rightChain = [ ] ; function compare2Objects ( x , y ) { let p ; if ( isNaN ( x ) && isNaN ( y ) && typeof x === 'number' && typeof y === 'number' ) { return true ; } if ( x === y ) { return true ; } if ( ( typeof x === 'function' && typeof y === 'function' ) || ( x instanceof Date && y instanceof Date ) || ( x instanceof RegExp && y instanceof RegExp ) || ( x instanceof String && y instanceof String ) || ( x instanceof Number && y instanceof Number ) ) { return x . toString ( ) === y . toString ( ) ; } if ( ! ( x instanceof Object && y instanceof Object ) ) { return false ; } if ( x . isPrototypeOf ( y ) || y . isPrototypeOf ( x ) ) { return false ; } if ( x . constructor !== y . constructor ) { return false ; } if ( leftChain . indexOf ( x ) > - 1 || rightChain . indexOf ( y ) > - 1 ) { return false ; } for ( p in y ) { if ( treatUndefinedAndMissingKeyAsSame && y . hasOwnProperty ( p ) && ! x . hasOwnProperty ( p ) && y [ p ] === undefined ) { continue ; } if ( y . hasOwnProperty ( p ) !== x . hasOwnProperty ( p ) ) { return false ; } else if ( typeof y [ p ] !== typeof x [ p ] ) { return false ; } } for ( p in x ) { if ( y . hasOwnProperty ( p ) !== x . hasOwnProperty ( p ) ) { if ( ! treatUndefinedAndMissingKeyAsSame || ! x . hasOwnProperty ( p ) || y . hasOwnProperty ( p ) || x [ p ] !== undefined ) { return false ; } } switch ( typeof ( x [ p ] ) ) { case 'object' : case 'function' : leftChain . push ( x ) ; rightChain . push ( y ) ; if ( ! compare2Objects ( x [ p ] , y [ p ] ) ) { return false ; } leftChain . pop ( ) ; rightChain . pop ( ) ; break ; default : if ( x [ p ] !== y [ p ] ) { return false ; } break ; } } return true ; } if ( arguments . length <= 1 ) { throw new Error ( 'Need two or more arguments to compare' ) ; } return compare2Objects ( _1 , _2 ) ; }