Deep Remove Falsy
Prompt
Implement a function deepRemoveFalsy(value) that returns a new value with all falsy values removed at every level of nesting. The input can be a primitive, an array, or an object.
The falsy values are: false, null, 0, '' (empty string), undefined, and NaN.
Empty objects {} and empty arrays [] that result from removing falsy values should also be removed.
Playground
Handle three cases: primitives (return as-is), arrays
(filter out falsy values, recurse into truthy ones), and
objects (skip falsy values, recurse into truthy ones). Use
Array.isArray() to distinguish arrays from objects.
After recursively cleaning a nested object or array, check if it's now empty. If an object has no keys or an array has no elements, it should be treated as "empty" and excluded from the result.
Solution
Explanation
This function cleans out all the junk from a data structure. Nulls, empty strings, zeros, false values, all of it, at every level of nesting. And if removing those values leaves an object or array empty, that gets removed too.
The three cases
The function handles three types of input:
Primitives (numbers, strings, booleans, null): just return them as-is. The filtering happens at the parent level, not here. If a parent sees a falsy primitive, it won't include it.
Arrays: first filter out falsy values with .filter(Boolean). Then recursively clean each remaining element with .map(deepRemoveFalsy). Finally, filter out any elements that became empty objects {} or empty arrays [] after cleaning.
Objects: loop through each key-value pair. Skip falsy values with if (!val) continue. For truthy values, recursively clean them. If the cleaned result is an empty object or array, don't include it in the output.
Why do we check for empty after cleaning?
Consider this input:
deepRemoveFalsy({ a: { b: null, c: 0 } });After removing falsy values from { b: null, c: 0 }, we're left with {}. An empty object. If we kept it, the result would be { a: {} }, which isn't useful. So we check: after cleaning, is this object empty? If yes, skip it entirely. The final result is {}.
This is the part that makes this question trickier than a simple filter(Boolean). You need to clean recursively, then check if the result is worth keeping.
Walking through a nested example
For { a: null, b: [false, { c: 0, d: 2 }], e: { f: '', g: 'hello' } }:
- Key
"a", valuenull. Falsy. Skip. - Key
"b", value[false, { c: 0, d: 2 }]. It's an array. Process it:- Filter falsy:
[{ c: 0, d: 2 }](false removed) - Recurse into
{ c: 0, d: 2 }: key"c"is0(falsy, skip), key"d"is2(truthy, keep). Result:{ d: 2 } - Not empty, keep it. Array becomes
[{ d: 2 }]
- Filter falsy:
- Key
"e", value{ f: '', g: 'hello' }. It's an object:- Key
"f"is''(falsy, skip). Key"g"is'hello'(truthy, keep). - Result:
{ g: 'hello' }
- Key
- Final:
{ b: [{ d: 2 }], e: { g: 'hello' } }
JavaScript's Boolean function is a handy shorthand for
filtering falsy values. [0, 1, false, 2, ''].filter(Boolean) is the same as .filter(item => !!item). It converts each value to a boolean and keeps
only the truthy ones.