function merge(target, ...sources) {
    for (const source of sources) {
        if (target === source) {
            throw new TypeError(
                'Cannot merge, target and source are the same'
            );
        }

        for (const key in source) {
            if (source[key] != null) {
                if (isObjectLike(source[key]) && isObjectLike(target[key])) {
                    merge(target[key], source[key]);
                    continue;
                } else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
                    target[key] = target[key].concat(source[key]);
                    continue;
                }
            }

            target[key] = source[key];
        }
    }

    return target;
}
Creates a new object with all nested object properties
merged into it recursively.

@param  {object}   target     - The target object.
@param  {object[]} ...sources - The source object(s).
@throws {TypeError} If the target and source are the same.
@return {object} Returns the `target` object.