v_is_empty_value
Simple checker for Empty/NotEmpty values. Checking Numbers, Null, NaN, Strings, Objects, Arrays, Maps, Sets, Symbols, Functions, BigInt, and more. Will also detect instances of Date, Promise, Error, RegExp, typed arrays, and return "not-empty" value for them.
General Information
It provides 4 core functions to check if a value is empty or not, plus a powerful configuration system.
Core Functions
isEmpty(v, options?): Checks if a value is empty. Returnstrueif empty,falseotherwise.isNotEmpty(v, options?): Checks if a value is not empty. Returnstrueif not empty,falseotherwise.isEmptyNested(v, options?): Checks if a nested value is empty (recursively checks Objects, Arrays, Maps, Sets). Handles circular references automatically.isNotEmptyNested(v, options?): Checks if a nested value is not empty.
Configuration System
Customize behavior globally or per-call:
config.get()- Get current configurationconfig.set(newConfig)- Update global configurationconfig.reset()- Reset to defaultscreateCustomChecker(config)- Create isolated checker with custom config
Configuration Options
| Option | Default | Description |
|---|---|---|
treatNaNAsEmpty |
true |
Treat NaN as empty |
treatFunctionAsEmpty |
true |
Treat functions as empty |
treatSymbolAsEmpty |
true |
Treat symbols as empty |
treatZeroBigIntAsEmpty |
false |
Treat 0n as empty |
checkCircular |
true |
Enable circular reference detection |
maxNestedDepth |
0 |
Max recursion depth (0 = unlimited) |
Base Example
// import { isEmpty, isNotEmpty, isEmptyNested, isNotEmptyNested } from 'v_is_empty_value'
const { isEmpty, isNotEmpty, isEmptyNested, isNotEmptyNested } = require('v_is_empty_value')
isEmpty(v) // Checks if a value is empty.
isNotEmpty(v) // Checks if a value is not empty.
isEmptyNested(v) // Checks if a nested value is empty.
isNotEmptyNested(v) // Checks if a nested value is not empty.
Things it confirms Empty
- Undefined / Empty
console.log(isEmpty()) // prints "true"
console.log(isNotEmpty()) // prints "false"
- Empty String
console.log(isEmpty('')) // prints "true"
console.log(isNotEmpty('')) // prints "false"
- null
console.log(isEmpty(null)) // prints "true"
console.log(isNotEmpty(null)) // prints "false"
- Undefined
console.log(isEmpty(undefined)) // prints "true"
console.log(isNotEmpty(undefined)) // prints "false"
- Empty Object
console.log(isEmpty({})) // prints "true"
console.log(isNotEmpty({})) // prints "false"
- Empty Array
console.log(isEmpty([])) // prints "true"
console.log(isNotEmpty([])) // prints "false"
Few things it confirms NOT Empty
- String with some length/value.
isEmpty('demo_password_123456') // prints "false"
isNotEmpty('demo_password_123456') // prints "true"
- Date instance.
isEmpty(new Date()) // prints "false"
isNotEmpty(new Date()) // prints "true"
- Error instance.
isEmpty(new Error()) // prints "false"
isNotEmpty(new Error()) // prints "true"
- Promise instance.
isEmpty(new Promise((resolve, reject) => resolve(true))) // prints "false"
isNotEmpty(new Promise((resolve, reject) => resolve(true))) // prints "true"
- RegExp instance.
isEmpty(/test/) // prints "false"
isEmpty(new RegExp('test')) // prints "false"
- Number (including
0and-0).
isEmpty(0) // prints "false"
isEmpty(-0) // prints "false"
isEmpty(42) // prints "false"
isEmpty(Number()) // prints "false" (Number() returns 0)
- Boolean (both
trueandfalse).
isEmpty(true) // prints "false"
isEmpty(false) // prints "false"
- BigInt (any value including
0nby default).
isEmpty(BigInt(0)) // prints "false"
isEmpty(BigInt(1)) // prints "false"
- Map/Set with entries.
isEmpty(new Map([['key', 'value']])) // prints "false"
isEmpty(new Set([1, 2, 3])) // prints "false"
- Typed Arrays.
isEmpty(new Uint8Array([1, 2, 3])) // prints "false"
- Nested Object : confirms not empty even though it has empty values (surface check only).
const nestedEmptyObject = {
demo: null,
yea: undefined,
iKnowMan: {
wtf: null,
moreNull: null
}
}
// NOTE: isEmpty() returns "false" because the object has keys.
console.log(isEmpty(nestedEmptyObject)) // prints "false"
console.log(isNotEmpty(nestedEmptyObject)) // prints "true"
// NOTE: Use "isEmptyNested(v)" to recursively check nested values.
console.log(isEmptyNested(nestedEmptyObject)) // prints "true"
console.log(isNotEmptyNested(nestedEmptyObject)) // prints "false"
More Info:
Check the test cases for more examples.
Configuration Examples
Global Configuration
Change behavior globally for all subsequent checks:
import { isEmpty, config } from 'v_is_empty_value'
// By default, NaN is treated as empty
isEmpty(NaN) // prints "true"
// Change global config to treat NaN as non-empty
config.set({ treatNaNAsEmpty: false })
isEmpty(NaN) // prints "false"
// Reset to defaults
config.reset()
isEmpty(NaN) // prints "true" again
Per-Call Options
Override configuration for a single call:
import { isEmpty } from 'v_is_empty_value'
// Global default: functions are empty
isEmpty(() => 'test') // prints "true"
// Override for this call only
isEmpty(() => 'test', { treatFunctionAsEmpty: false }) // prints "false"
Custom Checker
Create isolated checkers with different configs:
import { createCustomChecker } from 'v_is_empty_value'
const strictChecker = createCustomChecker({
treatNaNAsEmpty: false,
treatFunctionAsEmpty: false,
treatSymbolAsEmpty: false
})
const looseChecker = createCustomChecker({
treatZeroBigIntAsEmpty: true
})
// Strict checker
strictChecker.isEmpty(NaN) // false
strictChecker.isEmpty(() => {}) // false
// Loose checker
looseChecker.isEmpty(BigInt(0)) // true
� Lodash Drop-in Replacement
While v_is_empty_value defaults to semantically correct behavior, you can configure it to match Lodash's isEmpty() for drop-in compatibility:
import { isEmpty, config } from 'v_is_empty_value'
// Configure to match Lodash behavior
config.set({
treatNaNAsEmpty: true, // NaN is empty (same default)
treatFunctionAsEmpty: false, // Functions are NOT empty (Lodash style)
treatSymbolAsEmpty: false, // Symbols are NOT empty (Lodash style)
treatZeroBigIntAsEmpty: false, // 0n is NOT empty (same default)
nonEmptyTypes: [] // Disable Date/Promise/Error detection
})
// Now behaves like Lodash:
isEmpty(() => {}) // false (Lodash: false)
isEmpty(Symbol()) // false (Lodash: false)
isEmpty(new Date()) // true (Lodash: true - just checks Object.keys())
isEmpty(new Error()) // true (Lodash: true)
isEmpty(0) // false (Lodash: true ⚠️ STILL DIFFERENT!)
isEmpty(false) // false (Lodash: true ⚠️ STILL DIFFERENT!)
Why We Differ From Lodash
We intentionally differ from Lodash on these cases because we believe they are semantically incorrect:
| Value | Lodash | v_is_empty_value |
Rationale |
|---|---|---|---|
0 |
empty | non-empty | 0 is a valid numeric value, not "nothing" |
false |
empty | non-empty | false is a valid boolean state, not "no data" |
new Date() |
empty | non-empty | A Date instance represents a timestamp (has value) |
new Error() |
empty | non-empty | An Error represents an error condition (has value) |
new Promise() |
empty | non-empty | A Promise represents async state (has internal slots) |
Lodash uses Object.keys(value).length for objects, which returns 0 for class instances because their data is stored in internal slots, not enumerable properties. We detect these types via constructor.name and treat them as non-empty because they represent values even without enumerable properties.
Note: You cannot make 0 and false return true with configuration - these are hardcoded as non-empty because treating them as empty is considered a design flaw.
� Special Types Reference
| Type | Empty Behavior | Configurable |
|---|---|---|
undefined |
Empty (true) |
No |
null |
Empty (true) |
No |
'' (empty string) |
Empty (true) |
No |
NaN |
Empty (true) |
treatNaNAsEmpty |
Symbol |
Empty (true) |
treatSymbolAsEmpty |
Function |
Empty (true) |
treatFunctionAsEmpty |
0 |
Not empty (false) |
No |
BigInt(0) |
Not empty (false) |
treatZeroBigIntAsEmpty |
BigInt(n) |
Not empty (false) |
No |
true/false |
Not empty (false) |
No |
Date |
Not empty (false) |
No |
Promise |
Not empty (false) |
No |
Error |
Not empty (false) |
No |
RegExp |
Not empty (false) |
No |
Map (empty) |
Empty (true) |
No |
Map (entries) |
Not empty (false) |
No |
Set (empty) |
Empty (true) |
No |
Set (values) |
Not empty (false) |
No |
WeakMap/WeakSet |
Not empty (false) |
No |
ArrayBuffer |
Not empty (false) |
No |
| Typed Arrays | Not empty (false) |
No |
{} (empty object) |
Empty (true) |
No |
[] (empty array) |
Empty (true) |
No |
Circular Reference Handling
isEmptyNested() automatically handles circular references without infinite loops:
import { isEmptyNested } from 'v_is_empty_value'
const obj = { a: null, b: undefined }
obj.self = obj // Circular reference
// This works without hanging!
isEmptyNested(obj) // prints "true" (all values are empty)
const obj2 = { a: 'value' }
obj2.self = obj2 // Circular reference
isEmptyNested(obj2) // prints "false" (has non-empty value)
Performance Benchmark
This will basically run the functions mentioned for 25mil. times and will print the time taken for each function to complete.
Test setup
- AMD Ryzen 7 2700X Eight-Core Processor 3.70 GHz
- 16 GB 3000 MHz DDR4
- Patriot P300 256GB M.2 NVMe
- Windows 10 Pro 64-bit
- Node.js v20.10.0
Current performance (vs lodash.isEmpty)
| Metric | v_is_empty_value | lodash | Faster |
|---|---|---|---|
| Throughput | 23,978,672 ops/sec | 3,758,432 ops/sec | 6.4x |
| null | 0.89ms | 1.27ms | 1.4x |
| empty string | 0.72ms | 1.88ms | 2.6x |
| number 0 | 1.63ms | 6.75ms | 4.1x |
| NaN | 1.86ms | 5.34ms | 2.9x |
| empty Map | 5.98ms | 65.51ms | 11.0x |
| Map with entries | 3.36ms | 63.26ms | 18.8x |
| empty Set | 7.09ms | 73.90ms | 10.4x |
| Uint8Array | 4.01ms | 79.65ms | 19.9x |
| Promise | 4.08ms | 68.40ms | 16.7x |
| TOTAL | 91.75ms | 585.35ms | 6.4x |
Run npm run benchmark to see full comparison.
Release Process
For maintainers - steps to publish a new version:
Version Bump
npm version minor # or patch/majorPre-publish Check (runs lint, build, tests)
npm run prepackGit Commit & Tag
git add package.json git commit -m "chore: bump version to X.X.X" git tag vX.X.X git push origin main --tagsNPM Publish
npm publishGitHub Release (Recommended)
Go to GitHub repository → Releases → "Draft a new release"
Click "Choose a tag" and select
vX.X.XRelease title:
vX.X.X - Brief descriptionRelease notes:
## Changes - Feature/fix description - Performance improvements - Bug fixes ## Breaking Changes (if any) - Migration notesAttach build artifacts from
dist/folder (optional)Click "Publish release"
Related links :
- v_to_md5 MD5 hash generator
- v_to_sha256 sha256 hash generator
- v_file_system simple and safe fs module with sync and promises
- v_execute Exec cli commands
- v_scrolls Readme Generator
- v_database single database solution
- v_database_cli v_database cli tool