prune
Removes all nullable and empty values from strings, arrays, or objects. This utility recursively processes data structures to eliminate null, undefined, empty strings, empty arrays, and empty objects.
Implementation
View Source Code
ts
import { isArray } from '../typed/isArray';
import { isEmpty } from '../typed/isEmpty';
import { isNil } from '../typed/isNil';
import { isObject } from '../typed/isObject';
import { isString } from '../typed/isString';
/**
* Removes all nullable and empty values from strings, arrays, or objects.
*
* - For strings: Removes leading/trailing whitespace and returns undefined if empty
* - For arrays: Recursively removes null, undefined, empty strings, and empty objects/arrays
* - For objects: Recursively removes properties with null, undefined, empty strings, and empty objects/arrays
*
* @example
* ```ts
* prune(' hello '); // 'hello'
* prune(' '); // undefined
* prune([1, null, '', 2, undefined, 3]); // [1, 2, 3]
* prune({ a: 1, b: null, c: '', d: 2 }); // { a: 1, d: 2 }
* prune({ a: { b: null, c: '' }, d: 1 }); // { d: 1 }
* ```
*
* @param value - The value to prune (can be string, array, object, or any other type)
* @returns The pruned value, or undefined if the result would be empty
*/
export function prune<T>(value: T): T | undefined {
// Handle null/undefined
if (isNil(value)) {
return undefined;
}
// Handle strings
if (isString(value)) {
const trimmed = value.trim();
return (trimmed === '' ? undefined : trimmed) as T | undefined;
}
// Handle arrays
if (isArray(value)) {
const cleaned = value.map((item) => prune(item)).filter((item) => !isEmpty(item));
return (cleaned.length === 0 ? undefined : cleaned) as T | undefined;
}
// Handle objects
if (isObject(value)) {
const cleaned: Record<string, unknown> = {};
for (const [key, val] of Object.entries(value)) {
const cleanedValue = prune(val);
// Skip nil, empty strings, and empty arrays/objects
if (!isEmpty(cleanedValue)) {
cleaned[key] = cleanedValue;
}
}
return (Object.keys(cleaned).length === 0 ? undefined : cleaned) as T | undefined;
}
// For other types (numbers, booleans, etc.), return as-is
return value;
}Features
- Multi-Type Support: Works with strings, arrays, objects, and primitives
- Recursive Cleaning: Deep prunes nested structures
- String Trimming: Automatically trims whitespace from strings
- Empty Detection: Removes empty arrays and objects
- Type Preservation: Maintains proper TypeScript types
- Isomorphic: Works in both Browser and Node.js
API
ts
function prune<T>(value: T): T | undefined;Parameters
value: The value to prune (can be string, array, object, or any other type)
Returns
- The pruneed value with all nullable and empty values removed, or
undefinedif the result would be empty
Examples
String Cleaning
ts
import { prune } from '@vielzeug/toolkit';
prune(' hello '); // 'hello'
prune(' '); // undefined
prune(' world '); // 'world'
prune(''); // undefinedArray Cleaning
ts
import { prune } from '@vielzeug/toolkit';
// Remove null and undefined
prune([1, null, 2, undefined, 3]); // [1, 2, 3]
// Remove empty strings
prune(['hello', '', 'world', ' ']); // ['hello', 'world']
// Remove empty arrays and objects
prune([1, [], {}, 2]); // [1, 2]
// Trim strings in arrays
prune([' hello ', ' world ']); // ['hello', 'world']
// Nested arrays
prune([1, [2, null, 3], 4]); // [1, [2, 3], 4]Object Cleaning
ts
import { prune } from '@vielzeug/toolkit';
// Remove null and undefined properties
prune({ a: 1, b: null, c: 2, d: undefined }); // { a: 1, c: 2 }
// Remove empty strings
prune({ name: 'Alice', email: '', age: 30 }); // { name: 'Alice', age: 30 }
// Trim string values
prune({ first: ' John ', last: ' Doe ' }); // { first: 'John', last: 'Doe' }
// Remove empty arrays and objects
prune({ a: 1, b: [], c: {}, d: 2 }); // { a: 1, d: 2 }
// Nested objects
prune({
a: 1,
b: { c: null, d: 2 },
e: 3,
}); // { a: 1, b: { d: 2 }, e: 3 }Complex Nested Structures
ts
import { prune } from '@vielzeug/toolkit';
const data = {
name: 'Alice',
email: ' alice@example.com ',
age: 30,
address: {
street: '',
city: 'New York',
country: null,
},
hobbies: ['reading', '', null, 'coding'],
metadata: {
created: '2024-01-01',
tags: [],
notes: null,
},
};
prune(data);
/*
{
name: 'Alice',
email: 'alice@example.com',
age: 30,
address: {
city: 'New York'
},
hobbies: ['reading', 'coding'],
metadata: {
created: '2024-01-01'
}
}
*/Form Data Sanitization
ts
import { prune } from '@vielzeug/toolkit';
// Clean user input from forms
const formData = {
username: ' john_doe ',
email: 'john@example.com',
phone: '',
bio: ' ',
preferences: {
newsletter: true,
notifications: null,
theme: '',
},
};
const sanitized = prune(formData);
/*
{
username: 'john_doe',
email: 'john@example.com',
preferences: {
newsletter: true
}
}
*/API Response Cleaning
ts
import { prune } from '@vielzeug/toolkit';
// Clean API responses with optional fields
const apiResponse = {
id: 123,
name: 'Product',
description: null,
price: 99.99,
images: [],
tags: ['electronics', '', null, 'gadgets'],
metadata: {
created: '2024-01-01',
updated: null,
notes: '',
},
};
const pruneed = prune(apiResponse);
/*
{
id: 123,
name: 'Product',
price: 99.99,
tags: ['electronics', 'gadgets'],
metadata: {
created: '2024-01-01'
}
}
*/Primitive Types
ts
import { prune } from '@vielzeug/toolkit';
// Primitives are preserved
prune(42); // 42
prune(0); // 0
prune(true); // true
prune(false); // false
// Null and undefined become undefined
prune(null); // undefined
prune(undefined); // undefinedImplementation Notes
- String Handling: Trims leading/trailing whitespace and returns
undefinedfor empty strings - Zero Preservation: Numeric
0and booleanfalseare preserved (only null/undefined/empty strings are removed) - Deep Recursion: Processes nested structures at any depth
- Empty Results: Returns
undefinedif the pruneed result would be an empty array or object - Immutability: Creates new objects/arrays; does not modify input
- Object Properties: Only removes properties with truly empty values (not
0orfalse) - Performance: Uses efficient iteration; suitable for moderate-sized data structures