Lodash pickBy: Differentiating Undefined and Null

Lodash's _.pickBy method creates an object composed of properties that satisfy a specific predicate function, making it an effective tool for separating strictly undefined properties from explicit null values. Because JavaScript treats both null and undefined as falsy and loosely equal (null == undefined), default checks often conflate the two. By using custom predicates leveraging strict inequality or dedicated type-checking utilities like _.isUndefined and _.isNull, _.pickBy cleanly isolates these distinct property states during serialization or state sanitization.

The Default Behavior of _.pickBy

When called without a custom predicate, _.pickBy defaults to _.identity, which evaluates the truthiness of each property value:

const _ = require('lodash');

const data = {
  active: true,
  name: null,
  description: undefined,
  count: 0
};

// Default behavior removes all falsy values, including null, undefined, and 0
const result = _.pickBy(data);
// Output: { active: true }

Because _.identity removes all falsy values, both null and undefined are stripped indiscriminately.

Preserving null While Removing undefined

In APIs and databases, null often indicates intentional emptiness or a reset state, whereas undefined signals an absent or unprovided field. To drop strictly undefined keys while retaining null, supply a predicate that explicitly checks for strict inequality against undefined or uses _.isUndefined:

const payload = {
  id: 101,
  middleName: null,      // Explicitly set to empty
  nickname: undefined    // Missing / omitted
};

// Filter out only undefined values
const withoutUndefined = _.pickBy(payload, (value) => value !== undefined);

// Alternative using Lodash utilities:
// const withoutUndefined = _.pickBy(payload, _.negate(_.isUndefined));

console.log(withoutUndefined);
// Output: { id: 101, middleName: null }

In this implementation, middleName is kept intact because null !== undefined evaluates to true.

Preserving undefined While Removing null

Conversely, if the objective is to clean out explicitly null attributes while retaining undefined placeholders, apply a strict check against null or utilize _.isNull:

const payload = {
  id: 101,
  middleName: null,
  nickname: undefined
};

// Filter out only null values
const withoutNull = _.pickBy(payload, (value) => value !== null);

// Alternative using Lodash utilities:
// const withoutNull = _.pickBy(payload, _.negate(_.isNull));

console.log(withoutNull);
// Output: { id: 101, nickname: undefined }

Under the Hood: Why Strict Differentiation Works

Under the hood, _.pickBy iterates over an object’s own and inherited enumerable string-keyed properties using an internal loop (similar to baseForOwn). For every entry, it executes:

if (predicate(value, key)) {
  result[key] = value;
}

Because Lodash passes the exact reference of value directly to the predicate, JavaScript's strict identity operator (===) or Lodash’s type checkers (Object.prototype.toString.call via _.isNull / value === undefined via _.isUndefined) prevent type coercion. This guarantees that explicit null assignments are never conflated with missing or undefined keys.