merge-anything

Merge objects & other types recursively. A simple & small integration.

README

Merge anything 🥡


  1. ```
  2. npm i merge-anything
  3. ```

Merge objects & other types recursively. Fully TypeScript supported! A simple & small integration.

Motivation


I created this package because I tried a lot of similar packages that do merging/deepmerging/recursive object assign etc. But all had its quirks, and _all of them break things they are not supposed to break_... 😞

I was looking for:

- a simple merge function like Object.assign() but deep
- supports merging of nested properties
- supports TypeScript: the type of the result is what JS actually returns
- supports symbols
- supports enumerable & nonenumerable props
- does not break special class instances ‼️

This last one is crucial! In JavaScript almost everything is _an object_, sure, but I don't want a merge function trying to merge eg. two new Date() instances! So many libraries use custom classes that create objects with special prototypes, and such objects all break when trying to merge them. So we gotta be careful!

merge-anything will merge objects and nested properties, but only as long as they're "plain objects". As soon as a sub-prop is not a "plain object" and has a special prototype, it will copy that instance over "as is". ♻️

Meet the family (more tiny utils with TS support)



Usage


- Unlimited — Merge will merge an unlimited amount of plain objects you pass as the arguments
- Nested — Nested objects are merged deeply (see example below)
- No modification — Merge always returns a new object without modifying the original, but does keep object/array references for nested props.

  1. ```js
  2. import { merge } from 'merge-anything'

  3. const starter = { name: 'Squirtle', types: { water: true } }
  4. const newValues = { name: 'Wartortle', types: { fighting: true }, level: 16 }

  5. const evolution = merge(starter, newValues, { is: 'cool' })
  6. // returns {
  7. //   name: 'Wartortle',
  8. //   types: { water: true, fighting: true },
  9. //   level: 16,
  10. //   is: 'cool'
  11. // }
  12. ```

TypeScript Support


In the example above, if you are using TypeScript, and you hover over evolution, you can actually see the type of your new object right then and there. This is very powerful, because you can merge things, and without needing any, TypeScript will know exactly how your newly merged objects look!

typescript support

The return type of the merge() function is usable as a TypeScript utility as well:

  1. ```ts
  2. import type { Merge } from 'merge-anything'

  3. type A1 = { name: string }
  4. type A2 = { types: { water: boolean } }
  5. type A3 = { types: { fighting: boolean } }

  6. type Result = Merge<A1, [A2, A3]>
  7. ```

Rules


This package will recursively go through plain objects and merge the values onto a new object.

Please note that this package recognises special JavaScript objects like class instances. In such cases it will not recursively merge them like objects, but assign the class onto the new object "as is"!


  1. ```js
  2. // all passed objects do not get modified
  3. const a = { a: 'a' }
  4. const b = { b: 'b' }
  5. const c = { c: 'c' }
  6. const result = merge(a, b, c)
  7. // a === {a: 'a'}
  8. // b === {b: 'b'}
  9. // c === {c: 'c'}
  10. // result === {a: 'a', b: 'b', c: 'c'}
  11. // However, be careful with JavaScript object references with nested props. See below: A note on JavaScript object references

  12. // arrays get overwritten
  13. // (for "concat" logic, see Extensions below)
  14. merge({ array: ['a'] }, { array: ['b'] }) // returns {array: ['b']}

  15. // empty objects merge into objects
  16. merge({ obj: { prop: 'a' } }, { obj: {} }) // returns {obj: {prop: 'a'}}

  17. // but non-objects overwrite objects
  18. merge({ obj: { prop: 'a' } }, { obj: null }) // returns {obj: null}

  19. // and empty objects overwrite non-objects
  20. merge({ prop: 'a' }, { prop: {} }) // returns {prop: {}}
  21. ```

merge-anything properly keeps special objects intact like dates, regex, functions, class instances etc.

However, it's very important you understand how to work around JavaScript object references. Please be sure to read a note on JavaScript object references down below.