merge.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { isArray, isObject } from '../../type/type';
  2. import { forOwn } from '../forOwn/forOwn';
  3. /**
  4. * Merges U to T.
  5. *
  6. * @typeParam T - An object to merge to.
  7. * @typeParam U - An object to to.
  8. *
  9. * @return An merged object type.
  10. */
  11. export type Merge<T extends object, U extends object> = Omit<T, keyof U> & {
  12. [ K in ( keyof T & keyof U ) ]: U[ K ] extends object
  13. ? U[ K ] extends any[]
  14. ? T[ K ] extends any[]
  15. ? Array<T[ K ][ number ] | U[ K ][ number ]>
  16. : U[ K ]
  17. : T[ K ] extends object
  18. ? Merge<T[ K ], U[ K ]> extends infer A ? Cast<A, object> : never
  19. : U[ K ]
  20. : U[ K ];
  21. } & Omit<U, keyof T>;
  22. type Cast<T, U> = T extends U ? T : U;
  23. /**
  24. * Recursively merges source properties to the object.
  25. * Be aware that this method does not merge arrays. They are just duplicated by `slice()`.
  26. *
  27. * @param object - An object to merge properties to.
  28. * @param source - A source object to merge properties from.
  29. *
  30. * @return A new object with merged properties.
  31. */
  32. export function merge<T extends object, U extends object>( object: T, source: U ): Merge<T, U> {
  33. forOwn( source, ( value, key ) => {
  34. if ( isArray( value ) ) {
  35. object[ key ] = value.slice();
  36. } else if ( isObject( value ) ) {
  37. object[ key ] = merge( isObject( object[ key ] ) ? object[ key ] : {}, value );
  38. } else {
  39. object[ key ] = value;
  40. }
  41. } );
  42. return object as Merge<T, U>;
  43. }