Write compactObject(value). It takes a plain object or an array and returns a copy without the gaps, at every depth, the way you'd clean up form data or an API payload before sending it.
Drop every object key and array item whose value is null or undefined. The array items that stay move up to close the gaps, so the array gets shorter.
Also drop every plain object or array that's empty, including one that only becomes empty because everything inside it was dropped. The top level is never dropped: if nothing is left in it, return {} or [].
Keep everything else. 0, "", false, and NaN are values, not gaps. Walk only into arrays and plain objects (the kind {} and JSON.parse make): a date, a Map, a class instance, or a function is kept as it is, even when it holds nothing.
Don't change value: every plain object and array in the result is new.
compactObject({
name: "Ada",
email: null,
age: 0,
tags: ["math", undefined, null, "code"],
address: { street: undefined, city: null },
settings: { theme: { color: null }, alerts: [] },
});
// { name: "Ada", age: 0, tags: ["math", "code"] }
expect(compactObject({ a: 1, b: null, c: undefined, d: "x" })).toEqual({ a: 1, d: "x" });
const result = compactObject([1, null, 2, undefined, 3]);
expect(result).toEqual([1, 2, 3]);
expect(result).toHaveLength(3);
expect(compactObject({ a: 0, b: "", c: false, d: NaN })).toEqual({ a: 0, b: "", c: false, d: NaN });
expect(compactObject([0, "", false])).toEqual([0, "", false]);
expect(compactObject({ a: {}, b: [], c: 1 })).toEqual({ c: 1 });
expect(compactObject([[], {}, "x"])).toEqual(["x"]);
expect(compactObject({ a: { b: { c: null } }, d: [[null], {}], e: 1 })).toEqual({ e: 1 });
expect(compactObject({ list: [{ a: null, b: 1 }, { c: undefined }, [[], [null], [2]]] })).toEqual({ list: [{ b: 1 }, [[2]]] });
expect(compactObject({ a: null, b: { c: [] } })).toEqual({});
const list = compactObject([null, [undefined]]);
expect(Array.isArray(list)).toBe(true);
expect(list).toEqual([]);
class Empty {}
const when = new Date(0);
const map = new Map();
const instance = new Empty();
const fn = () => {};
const result = compactObject({ when, map, instance, fn });
expect(Object.keys(result).sort()).toEqual(["fn", "instance", "map", "when"]);
expect(result.when).toBe(when);
expect(result.map).toBe(map);
expect(result.instance).toBe(instance);
expect(result.fn).toBe(fn);
const input = { user: { name: "Ada", email: null }, tags: ["a", null], keep: { x: 1 } };
const result = compactObject(input);
expect(result).toEqual({ user: { name: "Ada" }, tags: ["a"], keep: { x: 1 } });
expect(result).not.toBe(input);
expect(result.keep).not.toBe(input.keep);
expect(input).toEqual({ user: { name: "Ada", email: null }, tags: ["a", null], keep: { x: 1 } });
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with Compact an object. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.