Skip to content

mapDeep

Recursively transforms the keys and/or values of a plain object — the deep counterpart to map, which only transforms the top level. Descends into nested plain objects and arrays of them; Date, Map, Set, class instances, and primitives are left untouched (only their position is walked into, matching cloneDeep’s notion of what counts as a plain-data node worth recursing into).

Both callbacks are optional and default to identity (no transformation). mapKey is called with the original key and value (before any recursive value transform); mapValue receives the already-recursed value. Entries whose mapped key is a prototype-polluting string (__proto__, constructor, prototype) are silently skipped, same as map.

Array elements also go through mapValue (with their stringified index as key, since arrays have no property keys of their own) — so values inside a plain array, not just object properties, get transformed too. mapKey is never called for array elements, since there is no key to rename.

Available since v3.0.3

import { mapDeep } from '@helpers4/object';
// or, from the all-in-one package (same code, one install):
import { mapDeep } from 'helpers4/object';
mapDeep<T>(obj: T, mapValue?: function, mapKey?: function): T
ParameterTypeDescription
objTThe value to transform (typically an object, or an array of objects)
mapValuefunctionCallback called with `(value, key)` for each entry’s (already-recursed) value. For array elements, `key` is the element’s index as a string. Defaults to identity. (optional)
mapKeyfunctionCallback called with `(key, value)` for each object entry. Defaults to identity. (optional)

T — A new value with every plain-object key/value transformed

Unlike map(), mapDeep() walks into nested objects and arrays of objects.

mapDeep({ a: { b: 1 } }, undefined, key => key.toUpperCase())
// => { A: { B: 1 } }

Values are visited after their own nested content has already been transformed.

mapDeep({ a: { b: 1, c: 2 } }, v => typeof v === 'number' ? v * 10 : v)
// => { a: { b: 10, c: 20 } }

Array elements are visited by mapValue as well, keyed by their stringified index.

mapDeep({ tags: [1, 2, 3] }, v => typeof v === 'number' ? v * 10 : v)
// => { tags: [10, 20, 30] }

View source on GitHub