Avoid the object/array check and treat the return value the same way with JavaScript spread operator? I'm trying to implement a function (a template-helper function) which provides a simple merge-like functionality for both arrays and objects. The two functions are basically looks identical:
const mergeArrays = (first, ...rest) =&gt;
  rest.reduce((acc, curr) =&gt; ([ ...acc, ...curr]), first);

const mergeObjects = (first, ...rest) =&gt;
  rest.reduce((acc, curr) =&gt; ({ ...acc, ...curr }), first);

One could do a type check and a local variable to write a single function like this:
const mergeArraysOrObjects1 = (first, ...rest) =&gt; {
  let reducer = null;
  if ('object' === typeof first &amp;&amp; null !== first) {
    reducer = (acc, curr) =&gt; ({ ...acc, ...curr });
  }
  if (Array.isArray(first)) {
    reducer = (acc, curr) =&gt; [...acc, ...curr];
  }

  if (!reducer) {
    throw new Error('The &quot;merge&quot; filter only works with arrays and hashes.');
  }

  return rest.reduce(reducer, first);
}

... but it seems so ugly to me. Another possibility is a type check and inline conditional:
const mergeArraysOrObjects2 = (first, ...rest) =&gt; {
  if ('object' !== typeof first || null === first) {
    throw new Error('The &quot;merge&quot; filter only works with arrays and hashes.');
  }

  return rest.reduce(
    (acc, curr) =&gt; Array.isArray(acc) ? [...acc, ...curr] : {...acc, ...curr},
    first
  );
}

I'm still learning JavaScript so I'm guessing if there is a more elegant and concise way to treat the return value the same way.
Object.assign &amp;&amp; Array.flat
By the first example which does not have any type checking makes the throwing of errors in the second two examples look superfluous, a little over kill.
As the function Array.isArray is the more concise statement over the always ugly object test typeof obj === &quot;Object &amp;&amp; obj !== null you can use a simple ternary to call the correct function
You can use Object.assign rather than the long and slow object by object reduce method to merge objects.
And for the array Array.push, then Array.flat(1) depth of 1 for the arrays. To ensure you do not effect the input array first you would also need to copy it to a new array
Examples.
const merge = (first, ...rest) =&gt; {
    const arrays = (arr) =&gt; (arr.push(...rest), arr.flat(1));
    const objects = () =&gt; Object.assign({}, first,  ...rest);        
    return Array.isArray(first) ? arrays([[...first]]) : objects();
}

Or a shortened form
const merge = (first, ...rest) =&gt; {
    return Array.isArray(first) ? 
         (first = [[...first]], first.push(...rest), first.flat(1)) : 
         Object.assign({}, first,  ...rest);
}

Update
Fixed bug as pointed out in comments.
From the same comment by ScottyJamison in which is presented an even better solution, using the rest operator on all the arguments resulting in...
const merge = (...items) =&gt; Array.isArray(items[0]) ? 
    items.flat(1) : 
    Object.assign({}, ...items);

or
const merge = (...items) =&gt; Array.isArray(items[0]) ? items.flat(1) : Object.assign({}, ...items);