Let's say I have this set up:
const objA = { name: "Jacob", email: "jacob@email.com" };
const objB = { lastName: "Smith" };
Why can I do this:
const lastName = objA.lastName || objB.lastName;
But not this?
const { lastName } = objA || objB;
Was able to re-create above example in dev tools.
My real world application: I have "normal" and "legacy" account roles, and after querying both types of roles, I'd like to be able to do:
const { schoolAdmin } = account || legacyAccount;
... but instead have to do:
const schoolAdmin = account.schoolAdmin || legacyAccount.schoolAdmin;
Which is admittedly not a big deal, but I feel like there's something I'm missing and that I could use destructuring here. Jr dev, sorry if this is a dummy question! (Sometimes there is no account, and sometimes there is an account that doesn't have the schoolAdmin role! Likewise with legacyAccount.)
Your expression is trying to assign lastName
from a property in the object returned from the sub-expression on the right side of the =
assignment operator. That right side sub-expression, objA || objB
evaluates to objA
, which has no lastName
property, so your lastName
variable receives a value of undefined
.
You could either just use objA
, and provide a default value from objB
, if the property doesn't exist in objA
:
const { lastName = objB.lastName } = objA;
Or, you can spread objA
and objB
into a single object, and destructure from that:
const { lastName } = { ...objB, ...objA };
When spreading, reverse the order. The last object spread overwrites values from the first object. So, if you want to prefer the value from objA
, list objA
last.
This spreading option provides a satisfying symmetry, but is likely to be less efficient. From a performance perspective, the first option is better. But, for me, personally, I think the code you don't like provides better clarity with performance as good as you can get:
const lastName = objA.lastName || objB.lastName;
This is completely unambiguous and performs no unnecessary operations.
It should also be pointed out that neither of my solutions is strictly equivalent to the non-destructuring approach. If objA.lastName
is a falsy value besides undefined
, (""
, null
, 0
, or false
), then objB.lastName
would be used, whereas in both of my solutions, the falsey objA.lastName
would be used. Thanks to VLAZ for mentioning this in the comments.