Lodash _.assignInWith() method
What you’ll learn
- How
_.assignInWith(object, ...sources, customizer)layers _.assignIn with a per-key decision callback. - The customizer signature
(objValue, srcValue, key, object, source)and theundefinedfallback rule. - Why this is shallow even with a customizer—and when to delegate to
_.mergeWithfor depth. - Try each example in the editor (
?tryit=1,2,3) with Lodash from a CDN.
Prerequisites
Read _.assignIn() first for the shared own-plus-inherited shallow semantics; this page focuses on the customizer.
- Callbacks: the customizer is a plain function called per key—treat
undefinedreturns as “skip”. - Immutability mindset: the customizer doesn’t change the shallow rule—return new objects yourself if you need fresh references for nested keys.
Overview
_.assignInWith is _.assignIn plus a callback. For every key Lodash would otherwise overwrite, it asks the customizer for a final value first. Return undefined and Lodash uses the incoming srcValue; return anything else and you decide.
Per-key control
Pick winners by key, combine numbers, concatenate strings, or guard against overwriting non-empty values.
undefined = fall through
Easy default: return undefined for keys you don’t care about and the source value wins as usual.
Still shallow
The walk stays one level deep—use _.mergeWith when you need recursive customization.
Syntax
_.assignInWith(object, [...sources], [customizer])
// alias: _.extendWith(object, [...sources], [customizer])
//
// customizer(objValue, srcValue, key, object, source) => any - object: destination; mutated in place.
- sources: zero or more source objects; own and inherited enumerable string keys are visited left to right.
- customizer: last argument; return
undefinedto accept the source value, anything else to override. - Returns: the (now-mutated) destination object.
- Skipped: symbol keys; non-enumerable properties; nested depth (use _.mergeWith).
Per-key rule with undefined fallback
Combine two values for the key "b"; let every other key fall through to the source. Returning undefined is the “do what you normally do” signal.
import assignInWith from "lodash/assignInWith";
const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { d: 5 };
function customizer(objValue, srcValue, key) {
if (key === "b") {
return (objValue || 0) * (srcValue || 1);
}
// undefined -> keep default behavior (srcValue wins)
}
assignInWith(target, source1, source2, customizer);
// target is now { a: 1, b: 6, c: 4, d: 5 } “Don’t overwrite existing” pattern
A common defaults-style customizer: keep the destination’s value when it already exists, otherwise let the source fill the gap.
import assignInWith from "lodash/assignInWith";
const userPrefs = { theme: "dark", lang: undefined };
const defaults = { theme: "light", lang: "en", fontSize: 14 };
function keepDefined(objValue, srcValue) {
return objValue === undefined ? srcValue : objValue;
}
assignInWith(userPrefs, defaults, keepDefined);
// userPrefs -> { theme: "dark", lang: "en", fontSize: 14 } Customizer also sees inherited keys
The “In” suffix means prototype keys are visited too—your callback runs for both own and inherited. Switch to _.assignWith when you only want own keys.
import assignInWith from "lodash/assignInWith";
function Source() {
this.own = "instance";
}
Source.prototype.inherited = "prototype";
const seen = [];
function tag(objValue, srcValue, key) {
seen.push(key);
return String(srcValue).toUpperCase();
}
assignInWith({}, new Source(), tag);
// seen -> ["own", "inherited"]
// result -> { own: "INSTANCE", inherited: "PROTOTYPE" } 📋 _.assignInWith vs _.assignWith vs _.mergeWith
| Topic | _.assignInWith | _.assignWith | _.mergeWith |
|---|---|---|---|
| Customizer signature | (objValue, srcValue, key, object, source) | Same | Same, plus stack for recursion |
| Own keys | Yes | Yes | Yes |
| Inherited keys | Yes | No | No |
| Depth | Shallow | Shallow | Recursive |
| Aliases | _.extendWith | — | — |
| Typical use | Per-key rules on class instances | Per-key rules on plain objects | Per-key rules inside deep configs |
Pick _.assignInWith when the source has meaningful prototype data and you need per-key logic; switch to _.mergeWith the moment you want depth.
Pitfalls to avoid
Forgetting the undefined fallback
A customizer that always returns a value (even null or empty string) overwrites every key. Return undefined for keys you want to leave to the default rule.
Customizer is not recursion
The callback fires once per top-level key. Use _.mergeWith if you actually need to walk into nested objects.
Destination is written in place
Pass {} as the first argument when callers share a reference and you need a fresh object.
❓ FAQ
Summary
- Purpose: shallow assignment of own + inherited string keys with a per-key customizer.
- Remember: customizer returns
undefined→ lodash usessrcValue; anything else → that value wins. - Next: Lodash _.assignWith(), _.assignIn(), or the official Lodash docs for _.assignInWith.
_.assignInWith’s customizer is the only knob: return undefined and lodash falls back to srcValue; return anything else and that wins for the current key. The signature (objValue, srcValue, key, object, source) is shared by _.assignWith and _.mergeWith—learn it once.
6 people found this page helpful
