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