const UNSET = typeof Symbol !== "undefined" ? Symbol("UNSET") : {}; interface Merge { (a: A): A; (a: A, b: B): A & B; (a: A, b: B, c: C): A & B & C; (a: A, b: B, c: C, d: D): A & B & C & D; (a: A, b: B, c: C, d: D, e: E): A & B & C & D & E; (a: A, b: B, c: C, d: D, e: E, f: F): A & B & C & D & E & F; (a: A, b: B, c: C, d: D, e: E, f: F, g: G): A & B & C & D & E & F & G; (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): A & B & C & D & E & F & G & H; (a: A, ...args: B[]): unknown; UNSET: typeof UNSET; } /** * Shallow merges given objects into new object. It does not mutate any object given. Allows removing properties as * well by assigning special merge.UNSET value. * @param {...object} args - input objects * @returns {*} */ const merge: Merge = (...args: MergeCandidate[]) => { const nonObjects = args.some(p => { const t = typeof p; return t === "string" || t === "number" || t === "symbol" || t === "boolean" || t === "function" || Array.isArray(p); }); if (nonObjects) { throw new TypeError("Only objects are allowed"); } const r: { [key: string]: unknown } = {}; args.forEach((obj) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition Object.entries(obj || {}).forEach(([key, value]) => { if (value === UNSET) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete r[key]; return; } r[key] = value; }); }); return r; }; merge.UNSET = UNSET; export { merge, };