merge.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import { Cast, Head, Push, Resolve, Shift } from '../../../types';
  2. import { slice } from '../../arrayLike';
  3. import { isArray, isObject } from '../../type/type';
  4. import { forOwn } from '../forOwn/forOwn';
  5. /**
  6. * Merges U to T.
  7. *
  8. * @typeParam T - An object to merge U into.
  9. * @typeParam U - An object to merge properties from.
  10. *
  11. * @return A merged object type.
  12. */
  13. export type Merge<T extends object, U extends object> = Omit<T, keyof U> & {
  14. [ K in ( keyof T & keyof U ) ]: U[ K ] extends object
  15. ? U[ K ] extends any[]
  16. ? U[ K ]
  17. : T[ K ] extends object
  18. ? Merge<T[ K ], U[ K ]> extends infer A ? Resolve<Cast<A, object>> : never
  19. : U[ K ]
  20. : U[ K ];
  21. } & Omit<U, keyof T>;
  22. /**
  23. * Recursively merges U[] to T.
  24. *
  25. * @typeParam T - An object to assign to.
  26. * @typeParam U - A tuple contains objects.
  27. *
  28. * @return An assigned object type.
  29. */
  30. export type Merged<T extends object, U extends object[], N extends number, C extends any[] = []> = {
  31. 0: T,
  32. 1: Merged<Merge<T, Head<U>>, Shift<U>, N, Push<C>>,
  33. }[ C['length'] extends N ? 0 : 1 ] extends infer A ? Cast<A, any> : never;
  34. export function merge<T extends object>( object: T ): T;
  35. export function merge<T extends object, U extends object[]>(
  36. object: T,
  37. ...sources: U
  38. ): Resolve<Merged<T, U, U['length']>>
  39. /**
  40. * Recursively merges source properties to the object.
  41. * Be aware that this method does not merge arrays. They are just duplicated by `slice()`.
  42. *
  43. * @param object - An object to merge properties to.
  44. *
  45. * @return A new object with merged properties.
  46. */
  47. export function merge<T extends object>( object: T ): any {
  48. // eslint-disable-next-line prefer-rest-params
  49. slice( arguments, 1 ).forEach( source => {
  50. forOwn( source, ( value, key ) => {
  51. if ( isArray( value ) ) {
  52. object[ key ] = value.slice();
  53. } else if ( isObject( value ) ) {
  54. object[ key ] = merge( {}, isObject( object[ key ] ) ? object[ key ] : {}, value );
  55. } else {
  56. object[ key ] = value;
  57. }
  58. } );
  59. } );
  60. return object;
  61. }