import { Cast, Head, Push, Resolve, Shift } from '../../../types'; import { slice } from '../../arrayLike'; import { isArray, isObject } from '../../type/type'; import { forOwn } from '../forOwn/forOwn'; /** * Merges U to T. * * @typeParam T - An object to merge U into. * @typeParam U - An object to merge properties from. * * @return A merged object type. */ export type Merge = Omit & { [ K in ( keyof T & keyof U ) ]: U[ K ] extends object ? U[ K ] extends any[] ? T[ K ] extends any[] ? Array : U[ K ] : T[ K ] extends object ? Merge extends infer A ? Resolve> : never : U[ K ] : U[ K ]; } & Omit; /** * Recursively merges U[] to T. * * @typeParam T - An object to assign to. * @typeParam U - A tuple contains objects. * * @return An assigned object type. */ export type Merged = { 0: T, 1: Merged>, Shift, N, Push>, }[ C['length'] extends N ? 0 : 1 ] extends infer A ? Cast : never; export function merge( object: T ): T; export function merge( object: T, ...sources: U ): Resolve> /** * Recursively merges source properties to the object. * Be aware that this method does not merge arrays. They are just duplicated by `slice()`. * * @param object - An object to merge properties to. * * @return A new object with merged properties. */ export function merge( object: T ): any { slice( arguments ).forEach( source => { forOwn( source, ( value, key ) => { if ( isArray( value ) ) { object[ key ] = value.slice(); } else if ( isObject( value ) ) { object[ key ] = merge( isObject( object[ key ] ) ? object[ key ] : {}, value ); } else { object[ key ] = value; } } ); } ); return object; }