/** Checks that passed value is object, but not a callable-object (function) */ export const isObject = ( obj ) : obj is Record < string , any > => ! ! obj && typeof obj === 'object' ; /** Checks that passed value is an object or function */ export const isObjectLike = ( obj ) : boolean => isObject ( obj ) || typeof obj === 'function' ; /** Checks if the passed value is primitive */ export const isPrimitive = ( obj ) : obj is string | number | boolean | symbol | undefined | null => obj === null || typeof obj === 'undefined' || typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || typeof obj === 'symbol' ; /** Checks that passed object is prototype of some class */ export const isPrototype = ( obj ) : boolean => Object . hasOwnProperty . call ( obj , 'constructor' ) ; /** Array-like type definition */ export type ArrayLike < T = any > = { [ key ] : T ; length : number ; } ; /** Checks that passed object is array-like */ export const isArrayLike = ( value ) : value is ArrayLike => { if ( ! value || typeof value !== 'object' ) return false ; if ( Array . isArray ( value ) ) return true ; if ( typeof value . length !== 'number' || value . length < 0 ) return false ; return ! value . length || Object . hasOwnProperty . call ( value , value . length - 1 ) ; } ; export type CopyPredicate = ( key : string , value : any ) => boolean ; /** Deep object compare */ export function deepCompare ( obj1 , obj2 ) { if ( Object . is ( obj1 , obj2 ) ) return true ; if ( typeof obj1 !== typeof obj2 ) return false ; if ( isObject ( obj1 ) && isObject ( obj2 ) ) { const keys1 = Object . keys ( obj1 ) ; const keys2 = Object . keys ( obj2 ) ; if ( keys1 . length !== keys2 . length ) return false ; return ! keys1 . some ( ( key ) => ! deepCompare ( obj1 [ key ] , obj2 [ key ] ) ) ; } return false ; } /** Find the closest property descriptor */ export function getPropertyDescriptor ( o , prop ) { let proto = o ; while ( proto ) { const desc = Object . getOwnPropertyDescriptor ( proto , prop ) ; if ( desc ) return desc ; proto = Object . getPrototypeOf ( proto ) ; } } returns export function defined < T > ( ... params ) { for ( const param of params ) { if ( param !== undefined ) return param ; } } /** Makes a plain copy of obj with properties satisfying the predicate
 * If no predicate provided copies all own properties */ export function copy < T > ( obj , predicate = ( ) : boolean => true ) { const result = Object . assign ( { } , obj || { } ) ; Object . keys ( result ) . forEach ( ( key ) => { ( ! predicate ( key , result [ key ] ) ) && delete result [ key ] ; } ) ; return result ; } /** Makes a flat copy without undefined keys */ export function copyDefinedKeys < T > ( obj ? ) { return copy ( obj || { } , ( key , value ) => value !== void 0 ) ; } /** Omit copying provided properties from object */ export function omit < T > ( obj , keys ) { return copy ( obj , key => ! keys . includes ( key ) ) ; } param target param path param value export const set = ( target , path , value ) : void => { const parts = ( path || '' ) . split ( '.' ) ; const depth = parts . length - 1 ; parts . reduce ( ( cur , key , index ) => { if ( index === depth ) return cur [ key ] = value ; return cur [ key ] = isObjectLike ( cur [ key ] ) ? cur [ key ] : { } ; } , target ) ; } ; param data param path param defaultValue export const get = ( data , path , defaultValue ? ) : any => { const parts = ( path || '' ) . split ( '.' ) ; const result = parts . reduce ( ( curr , key ) => { if ( isObjectLike ( curr ) ) return curr [ key ] ; return undefined ; } , data ) ; return typeof result === 'undefined' ? defaultValue : result ; } ; returns export function deepMerge < T > ( obj ) ; returns export function deepMerge < T , U > ( obj1 , obj2 ) ; returns export function deepMerge < T , U , V > ( obj1 , obj2 , obj3 ) ; returns export function deepMerge < T , U , V , W > ( obj1 , obj2 , obj3 , obj4 ) ; returns export function deepMerge ( ... objects ) ; export function deepMerge ( ... objects ) { return objects . reduce ( ( res , obj , index ) => { if ( index === 0 && Array . isArray ( obj ) ) res = [ ] ; isObject ( obj ) && Object . keys ( obj ) . forEach ( ( key ) => { const resultVal = res [ key ] ; const objectVal = obj [ key ] ; let mergeResult = objectVal ; if ( isObject ( objectVal ) ) { if ( typeof resultVal === 'undefined' ) mergeResult = deepMerge ( objectVal ) ; else if ( isObject ( resultVal ) ) mergeResult = deepMerge ( resultVal , objectVal ) ; } res [ key ] = mergeResult ; } ) ; return res ; } , { } ) ; }