es-toolkit-clean
v1.2.0
Published
A lightweight, TypeScript-first library for cleaning JavaScript objects by removing undefined values, empty strings, empty arrays, functions, and other unwanted properties. Built on es-toolkit for superior performance.
Downloads
129
Maintainers
Readme
es-toolkit-clean
A lightweight, TypeScript-first library for cleaning JavaScript objects by removing undefined values, empty strings, empty arrays, functions, and other unwanted properties. Built on es-toolkit for superior performance.
Why es-toolkit-clean?
Sometimes API responses contain properties filled with empty strings, undefined values, or functions that you want to remove. This library provides a configurable way to clean your data structures, similar to a more powerful version of _.compact for objects.
Features
- 🧹 Smart cleaning - Removes empty strings, undefined values, empty arrays, and functions by default
- 🔧 Fully configurable - Customize how each data type should be processed
- 📦 Lightweight - Small bundle size (ESM: ~4.21KB, CJS: ~7.37KB) uncompressed.
- 📱 Universal - Works in Node.js, browsers, and edge environments
- 🚀 TypeScript-first - Full TypeScript support with comprehensive type definitions
- ⚡ High performance - Built on es-toolkit for optimal speed
- 🎯 Dual format - Supports both ESM and CommonJS
Installation
npm install es-toolkit-cleanpnpm add es-toolkit-cleanyarn add es-toolkit-cleanQuick Start
import clean from 'es-toolkit-clean'
const messy = {
name: 'John',
email: '', // Empty string - will be removed
age: 0, // Zero - will be kept
active: true, // Boolean - will be kept
score: null, // Null - will be kept
undefined: undefined, // Undefined - will be removed
fn: () => {}, // Function - will be removed
tags: ['', 'valid', ' '], // Mixed array - empty strings removed
nested: {
value: 'keep',
empty: '',
spaces: ' '
}
}
const cleaned = clean(messy)
console.log(cleaned)
// Output:
// {
// name: 'John',
// age: 0,
// active: true,
// score: null,
// tags: ['valid'],
// nested: { value: 'keep' }
// }Core API
clean(obj) - Default Export
The main function for cleaning any data structure with default settings.
import clean from 'es-toolkit-clean'
// Clean an object
const result = clean({ name: 'test', empty: '', valid: 42 })
// → { name: 'test', valid: 42 }
// Clean an array
const cleanArray = clean(['valid', '', ' ', 'another'])
// → ['valid', 'another']
// Clean a string
const cleanString = clean(' hello world ')
// → 'hello world'createCleaner(config) - Custom Cleaning
Create a custom cleaner with specific configuration for different data types.
import { createCleaner, defaultProcessors } from 'es-toolkit-clean'
// Remove null values (default behavior keeps them)
const strictCleaner = createCleaner({
...defaultProcessors,
isNull: () => undefined // Remove nulls instead of keeping them
})
const result = strictCleaner({
name: 'test',
value: null,
empty: ''
})
// → { name: 'test' }
// Keep functions (default behavior removes them)
const keepFunctions = createCleaner({
...defaultProcessors,
isFunction: (fn) => fn // Keep functions instead of removing them
})
const withFn = keepFunctions({
name: 'test',
callback: () => 'hello',
empty: ''
})
// → { name: 'test', callback: [Function] }createProcessor(config) - Custom Value Processing
Create a custom processor for handling individual values.
import { createProcessor, defaultProcessors } from 'es-toolkit-clean'
// Custom string processing
const customProcessor = createProcessor({
...defaultProcessors,
isString: (str) => {
const trimmed = str.trim()
return trimmed ? trimmed.toUpperCase() : undefined
}
})
const processor = customProcessor
const result = processor(' hello world ', processor)
// → 'HELLO WORLD'processValue(value, processor) - Process Single Values
Process individual values using the default or a custom processor.
import { processValue, createProcessor } from 'es-toolkit-clean'
// Using default processor
const cleaned = processValue(' hello ', processValue)
// → 'hello'
// Using custom processor
const upperProcessor = createProcessor({
isString: (str) => str.trim().toUpperCase() || undefined
})
const result = processValue(' hello ', upperProcessor)
// → 'HELLO'Configuration Options
The defaultProcessors object defines how each data type is handled:
import { defaultProcessors } from 'es-toolkit-clean'
// Default configuration:
const config = {
isArray: cleanArray, // Recursively clean arrays, remove if empty
isBoolean: identity, // Keep all boolean values
isDate: identity, // Keep all date values
isFunction: noop, // Remove all functions
isNull: identity, // Keep all null values
isNumber: identity, // Keep all number values (including 0)
isObjectLike: cleanObject, // Clean class instances, convert to plain objects
isPlainObject: cleanObject, // Recursively clean objects, remove if empty
isString: cleanString, // Trim whitespace, remove if empty
isUndefined: noop, // Remove all undefined values
}Customization Examples
import { createCleaner, defaultProcessors } from 'es-toolkit-clean'
// Remove all falsy values except 0
const removeFalsy = createCleaner({
...defaultProcessors,
isNull: () => undefined,
isBoolean: (val) => val || undefined,
isString: (str) => str.trim() || undefined
})
// Custom number processing
const positiveNumbers = createCleaner({
...defaultProcessors,
isNumber: (num) => num > 0 ? num : undefined
})
// Custom array processing
const nonEmptyArrays = createCleaner({
...defaultProcessors,
isArray: (arr, clean) => {
const cleaned = arr.map(item => clean(item, clean))
.filter(item => item !== undefined)
return cleaned.length >= 2 ? cleaned : undefined // Require at least 2 items
}
})Advanced Examples
Complex Object Cleaning
import clean from 'es-toolkit-clean'
const apiResponse = {
user: {
id: 123,
name: 'John Doe',
email: '',
phone: ' ',
profile: {
bio: '',
avatar: 'https://example.com/avatar.jpg',
settings: {
theme: '',
notifications: true,
metadata: {}
}
}
},
posts: [
{ title: 'Hello', content: '', tags: ['', 'intro'] },
{ title: '', content: '', tags: [] },
{ title: 'World', content: 'Content here', tags: ['update', ''] }
],
emptyArray: [],
nullValue: null,
undefinedValue: undefined
}
const cleaned = clean(apiResponse)
console.log(cleaned)
// Output:
// {
// user: {
// id: 123,
// name: 'John Doe',
// profile: {
// avatar: 'https://example.com/avatar.jpg',
// settings: {
// notifications: true
// }
// }
// },
// posts: [
// { title: 'Hello', tags: ['intro'] },
// { title: 'World', content: 'Content here', tags: ['update'] }
// ],
// nullValue: null
// }Working with Different Data Types
import clean from 'es-toolkit-clean'
// Array cleaning
const messyArray = ['valid', '', ' ', null, undefined, 0, false, 'another']
const cleanedArray = clean(messyArray)
// → ['valid', null, 0, false, 'another']
// String cleaning
const messyString = ' hello world '
const cleanedString = clean(messyString)
// → 'hello world'
// Nested structures
const nested = {
level1: {
level2: {
level3: {
value: '',
keep: 'this'
},
empty: ''
},
alsoEmpty: []
}
}
const cleanedNested = clean(nested)
// → { level1: { level2: { level3: { keep: 'this' } } } }Class Instance Cleaning
The library automatically handles class instances by converting them to plain objects while cleaning their properties:
import clean, { createCleaner } from 'es-toolkit-clean'
class User {
constructor(data) {
this.name = data.name
this.email = data.email
this.role = data.role
}
}
class ApiResponse {
constructor(data) {
this.user = new User(data.user)
this.metadata = data.metadata
this.timestamp = new Date()
}
}
const response = new ApiResponse({
user: {
name: 'John',
email: '', // Empty string - will be removed
role: 'admin'
},
metadata: {
version: '', // Empty string - will be removed
source: 'api'
}
})
const cleaned = clean(response)
console.log(cleaned)
// Output: Plain object (not ApiResponse instance)
// {
// user: { name: 'John', role: 'admin' },
// metadata: { source: 'api' },
// timestamp: 2025-06-10T12:00:00.000Z
// }
// Class instances become plain objects
console.log(cleaned.constructor.name) // → 'Object'
console.log(response.constructor.name) // → 'ApiResponse'The library intelligently distinguishes between:
- Class instances (converted to plain objects and cleaned)
- Plain objects (cleaned in place)
- Special objects (Date, RegExp, Map, Set, Error - preserved as-is)
import clean from 'es-toolkit-clean'
const mixed = {
classInstance: new User({ name: 'test', email: '' }),
plainObject: { value: 'keep', empty: '' },
date: new Date(),
regex: /pattern/g,
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3])
}
const result = clean(mixed)
// → {
// classInstance: { name: 'test' }, // Class → plain object, cleaned
// plainObject: { value: 'keep' }, // Plain object, cleaned
// date: 2025-06-10T12:00:00.000Z, // Date preserved
// regex: /pattern/g, // RegExp preserved
// map: Map(1) { 'key' => 'value' }, // Map preserved
// set: Set(3) { 1, 2, 3 } // Set preserved
// }Helper Functions
The library also exports individual helper functions for specific use cases:
import { cleanArray, cleanObject, cleanString } from 'es-toolkit-clean'
// Clean individual strings
const cleaned = cleanString(' hello ') // → 'hello'
const empty = cleanString(' ') // → undefined
// Clean arrays with custom processor
import { createProcessor } from 'es-toolkit-clean'
const processor = createProcessor()
const cleanedArray = cleanArray(['test', '', 'valid'], processor)
// → ['test', 'valid']
// Clean objects with custom processor
const cleanedObject = cleanObject({
name: 'test',
empty: '',
value: 42
}, processor)
// → { name: 'test', value: 42 }TypeScript Support
The library is written in TypeScript and provides comprehensive type definitions:
import clean, {
createCleaner,
createProcessor,
defaultProcessors,
type ProcessorConfig,
type CleanerFunction
} from 'es-toolkit-clean'
// Custom processor with full type safety
const customCleaner: CleanerFunction = createCleaner({
...defaultProcessors,
isString: (str: string): string | undefined => {
return str.length > 5 ? str.toLowerCase() : undefined
}
})
interface User {
name: string
email?: string
age: number
}
const user: User = { name: 'John', email: '', age: 25 }
const cleaned = clean(user) // Fully typedPerformance
Built on es-toolkit, this library offers excellent performance characteristics:
- Tree-shakable: Only include the functions you use
- Zero dependencies: Apart from es-toolkit core functions
- Optimized algorithms: Efficient recursive processing
- Memory efficient: Creates new objects without mutating originals
Development
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Build the library
pnpm build
# Type checking
pnpm typecheck
# Linting
pnpm lintAPI Reference
Functions
| Function | Description | Parameters | Returns |
|----------|-------------|------------|---------|
| clean(obj) | Clean any data structure with default settings | obj: unknown | unknown |
| createCleaner(config) | Create custom cleaner function | config: Partial<ProcessorConfig> | (obj: unknown) => unknown |
| createProcessor(config) | Create custom value processor | config: Partial<ProcessorConfig> | CleanerFunction |
| processValue(value, processor) | Process single value | value: unknown, processor: CleanerFunction | unknown |
Configuration
| Property | Type | Default Behavior | Customizable |
|----------|------|------------------|--------------|
| isArray | (arr: unknown[], clean: CleanerFunction) => unknown | Recursively clean, remove if empty | ✅ |
| isBoolean | (val: boolean) => unknown | Keep all booleans | ✅ |
| isDate | (date: Date) => unknown | Keep all dates | ✅ |
| isFunction | (fn: Function) => unknown | Remove all functions | ✅ |
| isNull | (val: null) => unknown | Keep all nulls | ✅ |
| isNumber | (num: number) => unknown | Keep all numbers | ✅ |
| isObjectLike | (obj: Record<string, unknown>, clean: CleanerFunction) => unknown | Clean class instances, convert to plain objects | ✅ |
| isPlainObject | (obj: Record<string, unknown>, clean: CleanerFunction) => unknown | Recursively clean, remove if empty | ✅ |
| isString | (str: string) => unknown | Trim, remove if empty | ✅ |
| isUndefined | (val: undefined) => unknown | Remove all undefined | ✅ |
License
MIT © Serhii Siryk
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
