Skip to content

Commit f96a61b

Browse files
feat: add removeAllFalsy option (#128)
* feat: add removeAllFalsy option * Remove second export
1 parent cbe07a7 commit f96a61b

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,17 @@ The following items will NOT be removed:
3131

3232
* Empty string, `''`
3333
* Null, `null`
34+
35+
## Options
36+
37+
### `removeAllFalsy`
38+
39+
Optional boolean.
40+
If provided, the empty string `''` and `null` will be removed as well.
41+
42+
```js
43+
import removeUndefinedObjects from 'remove-undefined-objects';
44+
45+
console.log(removeUndefinedObjects({key1: null, key2: 123, key3: ''}), {removeAllFalsy: true});
46+
// { key2: 123 }
47+
```

src/index.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,43 @@ function isEmptyObject(obj: unknown) {
66
return typeof obj === 'object' && obj !== null && !Object.keys(obj).length;
77
}
88

9+
interface RemovalOptions {
10+
removeAllFalsy?: boolean;
11+
}
12+
913
// Modified from here: https://stackoverflow.com/a/43781499
10-
function stripEmptyObjects(obj: any) {
14+
function stripEmptyObjects(obj: any, options: RemovalOptions = {}) {
1115
const cleanObj = obj;
1216

17+
if (obj === null && options.removeAllFalsy) {
18+
return undefined;
19+
}
20+
1321
if (!isObject(obj) && !Array.isArray(cleanObj)) {
1422
return cleanObj;
15-
} else if (obj === null) {
16-
return undefined;
1723
}
1824

1925
if (!Array.isArray(cleanObj)) {
2026
Object.keys(cleanObj).forEach(key => {
2127
let value = cleanObj[key];
2228

23-
if (typeof value === 'object' && value !== null) {
24-
value = stripEmptyObjects(value);
29+
if (typeof value !== 'object') {
30+
return;
31+
}
2532

26-
if (isEmptyObject(value)) {
33+
if (value === null) {
34+
if (options.removeAllFalsy) {
2735
delete cleanObj[key];
28-
} else {
29-
cleanObj[key] = value;
3036
}
31-
} else if (value === null) {
32-
// Null properties in an object should remain!
37+
return;
38+
}
39+
40+
value = stripEmptyObjects(value, options);
41+
42+
if (isEmptyObject(value)) {
43+
delete cleanObj[key];
44+
} else {
45+
cleanObj[key] = value;
3346
}
3447
});
3548

@@ -39,7 +52,7 @@ function stripEmptyObjects(obj: any) {
3952
cleanObj.forEach((o, idx) => {
4053
let value = o;
4154
if (typeof value === 'object' && value !== null) {
42-
value = stripEmptyObjects(value);
55+
value = stripEmptyObjects(value, options);
4356

4457
if (isEmptyObject(value)) {
4558
delete cleanObj[idx];
@@ -57,7 +70,7 @@ function stripEmptyObjects(obj: any) {
5770
return cleanObj.filter(el => el !== undefined);
5871
}
5972

60-
export default function removeUndefinedObjects<T>(obj?: T): T | undefined {
73+
export default function removeUndefinedObjects<T>(obj?: T, options?: RemovalOptions): T | undefined {
6174
if (obj === undefined) {
6275
return undefined;
6376
}
@@ -68,7 +81,7 @@ export default function removeUndefinedObjects<T>(obj?: T): T | undefined {
6881
let withoutUndefined = JSON.parse(JSON.stringify(obj));
6982

7083
// Then we recursively remove all empty objects and nullish arrays.
71-
withoutUndefined = stripEmptyObjects(withoutUndefined);
84+
withoutUndefined = stripEmptyObjects(withoutUndefined, options);
7285

7386
// If the only thing that's leftover is an empty object then return nothing.
7487
if (isEmptyObject(withoutUndefined)) return undefined;

test/index.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ test('should leave primitives alone', () => {
2020
expect(removeUndefinedObjects(undefined)).toBeUndefined();
2121
});
2222

23+
test('should leave only truthy primitives alone when removeAllFalsy is true', () => {
24+
expect(removeUndefinedObjects(1234, { removeAllFalsy: true })).toBe(1234);
25+
expect(removeUndefinedObjects('1234', { removeAllFalsy: true })).toBe('1234');
26+
expect(removeUndefinedObjects(null, { removeAllFalsy: true })).toBeUndefined();
27+
expect(removeUndefinedObjects(undefined, { removeAllFalsy: true })).toBeUndefined();
28+
});
29+
30+
test("should also remove '' and null values when removeAllFalsy is true", () => {
31+
expect(removeUndefinedObjects({ value: 1234 }, { removeAllFalsy: true })).toStrictEqual({ value: 1234 });
32+
expect(removeUndefinedObjects({ value: '1234' }, { removeAllFalsy: true })).toStrictEqual({ value: '1234' });
33+
expect(removeUndefinedObjects({ value: null }, { removeAllFalsy: true })).toBeUndefined();
34+
expect(removeUndefinedObjects({ value: undefined }, { removeAllFalsy: true })).toBeUndefined();
35+
});
36+
2337
test('should remove empty objects with only empty properties', () => {
2438
const obj = {
2539
a: {
@@ -66,6 +80,25 @@ test('should remove empty arrays from within object', () => {
6680
});
6781
});
6882

83+
test('should remove empty arrays and falsy values from within object when removeAllFalsy is true', () => {
84+
const obj = {
85+
a: {
86+
b: undefined,
87+
c: {
88+
d: undefined,
89+
},
90+
},
91+
d: [1234, undefined],
92+
e: [],
93+
f: null,
94+
g: [null, undefined, null],
95+
};
96+
97+
expect(removeUndefinedObjects(obj, { removeAllFalsy: true })).toStrictEqual({
98+
d: [1234],
99+
});
100+
});
101+
69102
test('should remove undefined and null values from arrays', () => {
70103
expect(removeUndefinedObjects([undefined, undefined])).toBeUndefined();
71104
expect(removeUndefinedObjects([null])).toBeUndefined();

0 commit comments

Comments
 (0)