I have two setting config
const defaultSetting = {
level1: {
setting1: "defaultValue1",
nested: true,
home: "africa"
},
level2: {
setting2: "defaultValue3"
}
};
const initialSetting = {
level1: {
setting1: "initialValue1", // This value will override defaultSetting's value
nested: false // This value will override defaultSetting's value
},
level2: {
nested: true // This value will override defaultSetting's value, adding a new property not in defaultSetting's level2
}
};
What I am trying to achieve is that I want to merge initialSetting into defaultSetting, such that:
- The structure of defaultSetting dictates the final structure.
- Values from initialSetting overwrite those in defaultSetting where they
exist. - If initialSetting contains keys not present in
defaultSetting, they are not included in the final object. - If defaultSetting contains keys not present in initialSetting, their
default values are retained.
I want to strictly adhere to the structure of defaultSetting while selectively pulling in values from initialSetting.
I have this code
const mergeTwoObjects = (obj11: NestedObject | undefined, obj2: NestedObject): unknown => {
const result: NestedObject = {};
const obj1 = obj11 ?? {};
(Object.keys(obj2) as Array<keyof typeof obj2>).forEach((key) => {
if (Object.prototype.hasOwnProperty.call(obj1, key)) {
if (typeof obj1[key] === "object" && typeof obj2[key] === "object") {
result[key] = mergeTwoObjects(
obj1[key] as NestedObject,
obj2[key] as NestedObject,
) as NestedObject;
} else {
result[key] = obj1[key];
}
} else {
result[key] = obj2[key];
}
});
return result;
};
But the requirement came as that I can not build my function from scratch rather than that I should be using lodash and make code simple without many loops
I tried this but it did not work
const defaultSetting = {
level1: {
setting1: "defaultValue1",
nested: true,
home: "africa"
},
level2: {
setting2: "defaultValue3"
}
};
const initialSetting = {
level1: {
setting1: "initialValue1", // This value will override defaultSetting's value
nested: false // This value will override defaultSetting's value
},
level2: {
nested: true // This value will override defaultSetting's value, adding a new property not in defaultSetting's level2
}
};
function mergeSettings(defaultSetting, initialSetting) {
return _.mergeWith({}, defaultSetting, initialSetting, (objValue, srcValue, key, object, source, stack) => {
if (_.isObject(objValue) && _.isObject(srcValue)) {
// Return undefined to let _.mergeWith handle the deep merge of these objects
return undefined;
}
// If srcValue is undefined, use objValue (from defaultSetting)
return srcValue === undefined ? objValue : srcValue;
});
}
const finalSetting = mergeSettings(defaultSetting, initialSetting);
console.log(finalSetting);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
I am new to Lodash, can anyone please help me achieve this
What I want to get is:
{
"level1": {
"setting1": "initialValue1",
"nested": false,
"home": "africa"
},
"level2": {
"setting2": "defaultValue3",
}
}
2
Answers
This is not possible in the exact sense with lodash methods. The closest you can do it nullify all values coming from object not present in the initial object. Otherwise use a combination of
mergeWith
andomit
. An example with missing values as null:If I’m not overlooking something, this relatively simple recursive function
merge
should do the trick (no library required):