I need to create an empty object at a deep path but only if it is not exist and return a reference to that object.
This can be accomplished by using _.has, _.set and then _.get
let path = 'some.deep.path';
if (!_.has(object, path)) {
    _.set(object, path, {});
}
let descendant = _.get(object, path);
What I would like instead, is to avoid repeating the object, path (or introducing the path variable to avoid repeating the path value)
I wonder if there's a way to do that without extra function/library.
This includes methods that deal with arrays/collections and accept the _.property iteratee/predicate shorthand, i.e. when a string is provided as an argument, it is passed over to the _.property method that creates a function which returns the value at path of a given object (that was given by the main function, e.g. _.map).
Array
Collection
Math
Object
Util
Seq
Chained methods, i.e. methods that are called in a sequence, e.g.:
_(value).chained().method().value();
You can avoid the _.has with this:
var path = 'some.deep.path',
descendant = _.get(object, path);
if (!descendant) {
    descendant = {};
    _.set(object, path, descendant);
}
Thus traversing the path only 2 times, instead of 3.
There's a _.deepDefault method in an extra lodash-deep library that checks if the value at the propertyPath resolves to undefined, and sets it to defaultValue if this is the case:
var descendant = _.deepDefault(object, 'some.deep.path', {});
That library is not updated anymore because Lodash now supports most of the functionality natively so here's an implementation as a lodash mixin function:
function getOrSetDefault(object, path, defaultValue) {
    const descendant = _.get(object, path);
    if (descendant === undefined) {
        _.set(object, path, defaultValue);
    }
    return descendant;
}
_.mixin({ getOrSetDefault });
const a = _.getOrSetDefault(object, 'some.deep.path', 42);
const b = _.getOrSetDefault(object, 'some.other.deep.path', {});
b.c = 42;
With the new optional chaining operator and a logical nullish assignment there would be no need to use lodash for this particular case (if it is acceptable to populate/define some.deep.path with a default value), e.g.:
some?.deep?.path ??= {}
const { foo } = some.deep.path
Unfortunately optional chaining assignments are not available yet. See https://stackoverflow.com/a/58882121/1949503
There would be just one drawback in that there'll be a need to repeat property accessors (some.deep.path) to retrieve the value. However in this case we will have autocompletion using Typescript/JSDoc unlike in lodash funcions' path argument (either string or array)
If there's only a need to get value at path the vanilla try/catch could be sufficient:
let foo: Foo;
try {
  foo = some.deep.path.foo
} catch {}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With