Skip to content
Version

prune

The prune utility recursively removes null, undefined, empty strings, and empty objects/arrays from a value. It works on strings, arrays, and objects, returning undefined when the entire value would be empty after pruning.

Source Code

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 {
  if (isNil(value)) return undefined;

  if (isString(value)) {
    const trimmed = value.trim();

    return (trimmed === '' ? undefined : trimmed) as T | undefined;
  }

  if (isArray(value)) {
    const cleaned = value.map((item) => prune(item)).filter((item) => !isEmpty(item));

    return (cleaned.length === 0 ? undefined : cleaned) as T | undefined;
  }

  if (isObject(value)) {
    const cleaned: Record<string, unknown> = {};

    for (const [key, val] of Object.entries(value)) {
      const cleanedValue = prune(val);

      if (!isEmpty(cleanedValue)) {
        cleaned[key] = cleanedValue;
      }
    }

    return (Object.keys(cleaned).length === 0 ? undefined : cleaned) as T | undefined;
  }

  return value;
}

Features

  • Recursive: Deeply cleans nested structures.
  • Multi-type: Works on strings, arrays, and objects with the same API.
  • Edge-safe: Returns undefined rather than empty containers.

API

ts
function prune<T>(value: T): T | undefined;

Parameters

  • value: The value to prune. Can be a string, array, object, or any other type (passthrough).

Returns

  • The pruned value, or undefined if the result would be entirely empty.

Examples

Strings

ts
import { prune } from '@vielzeug/toolkit';

prune('  hello  '); // 'hello'
prune('   '); // undefined
prune(''); // undefined

Arrays

ts
import { prune } from '@vielzeug/toolkit';

prune([1, null, '', 2, undefined, 3]); // [1, 2, 3]
prune([null, undefined, '']); // undefined

Objects

ts
import { prune } from '@vielzeug/toolkit';

prune({ a: 1, b: null, c: '', d: 2 });
// { a: 1, d: 2 }

prune({ a: { b: null, c: '' }, d: 1 });
// { d: 1 }

prune({ a: null, b: undefined });
// undefined

Sanitising API Payloads

ts
import { prune } from '@vielzeug/toolkit';

const formData = {
  name: '  Alice  ',
  email: '',
  address: {
    street: '123 Main St',
    apartment: '',
    city: 'Wonderland',
  },
  tags: ['typescript', null, '', 'toolkit'],
};

prune(formData);
/*
{
  name: 'Alice',
  address: { street: '123 Main St', city: 'Wonderland' },
  tags: ['typescript', 'toolkit'],
}
*/

See Also

  • diff: Find differences between two objects.
  • merge: Deep-merge cleaned objects.