Skip to content
Merged
38 changes: 31 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,32 @@ interface RemovalOptions {
removeAllFalsy?: boolean;
}

// Remove objects that has undefined value or recursively contain undefined values
function removeUndefined(obj: any): any {
if (obj === undefined) {
return undefined;
}
// Preserve null
if (obj === null) {
return null;
}
// Remove undefined in arrays
if (Array.isArray(obj)) {
return obj.map(removeUndefined).filter(item => item !== undefined);
}
if (typeof obj === 'object') {
const cleaned: any = {};
Object.entries(obj).forEach(([key, value]) => {
const cleanedValue = removeUndefined(value);
if (cleanedValue !== undefined) {
cleaned[key] = cleanedValue;
}
});
return cleaned;
}
return obj;
}

// Modified from here: https://stackoverflow.com/a/43781499
function stripEmptyObjects(obj: any, options: RemovalOptions = {}) {
const cleanObj = obj;
Expand Down Expand Up @@ -59,8 +85,7 @@ function stripEmptyObjects(obj: any, options: RemovalOptions = {}) {
} else {
cleanObj[idx] = value;
}
} else if (value === null) {
// Null entries within an array should be removed.
} else if (value === null && options.removeAllFalsy) {
delete cleanObj[idx];
}
});
Expand All @@ -75,12 +100,11 @@ export default function removeUndefinedObjects<T>(obj?: T, options?: RemovalOpti
return undefined;
}

// JSON.stringify removes undefined values. Though `[undefined]` will be converted with this to
// `[null]`, we'll clean that up next.
// eslint-disable-next-line try-catch-failsafe/json-parse
let withoutUndefined = JSON.parse(JSON.stringify(obj));
// Remove objects that recursively contain undefined values
// E.g. { a: { b: undefined } } -> { a: {} }
let withoutUndefined = removeUndefined(obj);

// Then we recursively remove all empty objects and nullish arrays.
// Then we recursively remove all empty objects and nullish arrays
withoutUndefined = stripEmptyObjects(withoutUndefined, options);

// If the only thing that's leftover is an empty object then return nothing.
Expand Down
6 changes: 4 additions & 2 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ test('should remove empty arrays from within object', () => {
expect(removeUndefinedObjects(obj)).toStrictEqual({
d: [1234],
f: null,
g: [null, null],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this appearing now?

});
});

Expand All @@ -99,11 +100,12 @@ test('should remove empty arrays and falsy values from within object when remove
});
});

test('should remove undefined and null values from arrays', () => {
test('should remove undefined values from arrays & not null values', () => {
expect(removeUndefinedObjects([undefined, undefined])).toBeUndefined();
expect(removeUndefinedObjects([null])).toBeUndefined();
expect(removeUndefinedObjects([null])).toStrictEqual([null]);
expect(removeUndefinedObjects(['1234', null, undefined, { a: null, b: undefined }, ' ', ''])).toStrictEqual([
'1234',
null,
{
a: null,
},
Expand Down