Avoid the object/array check and treat the return value the same way with JavaScript spread operator?
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);