Succinct/concise syntax for 'optional' object keys in ES6/ES7? [duplicate]
Asked Answered
L

4

117

There are already a lot of cool features in ES6/ES7 for defining Javascript objects. However, the following pattern is common in Javascript:

const obj = { 
  requiredKey1: ..., 
  requiredKey2: ... 
};

if (someCondition) { 
  obj.optionalKey1 = ...;
}

Is there a way to define the object all at once with both optional and required keys?

Larhondalari answered 19/12, 2017 at 17:18 Comment(5)
Why not just use a ternary? optionKey1: someCondition ? value : undefined?Endermic
@FelixKling I think that's a largely theoretical distinction because there is not a 'whole' ES6 or ES7 standard implemented in Node/browser environments and most people are using transpilers anyway.Larhondalari
Well, it defines the scope for answers. We don’t know what you are using. Also I don’t want people to misuse the term ES7 for experimental features.Viridis
@FelixKling I'm asking about any standard of Ecmascript; obviously existing supported standards is better. If this can be done with experimental features, okay. If it can be done with ES6 or ES7, better. If it is possible with ES5, super!Larhondalari
I would love to see something like { key?: optionalValue } or with property shorthand: { optionalValue? }Heaver
P
311

You can use object spread to have an optional property:

let flag1 = true;
let flag2 = false;

// extra cases added by Abdull
let optionalKey8 = 8;
let optionalKey9 = undefined;
let optionalKey10 = false;
let optionalKey11 = null;
let optionalKey12 = "twelve";

const obj = { 
  requiredKey1: 1, 
  requiredKey2: 2,
  ...(flag1 && { optionalKey3: 3 }),
  ...(flag2 && { optionalKey4: 4, optionalKey5: 5 }),  // ignored
  ...(flag1 && { optionalKey6: 6, optionalKey7: 7 }),
  ...(optionalKey8 && { optionalKey8 }),
  ...(optionalKey9 && { optionalKey9 }), // ignored
  ...(optionalKey10 && { optionalKey10 }), // ignored
  ...(optionalKey11 && { optionalKey11 }), // ignored
  ...(optionalKey12 && { optionalKey12 })
};

console.log(obj);
Pogue answered 19/12, 2017 at 17:22 Comment(9)
Note: this will make turn any getters into static values.Cliftonclim
As a note, you don't need the parentheses. eg. ...flag1 && { optionalKey1: 5 }, is fine too.Pauli
@RyanKing can you give a sample ? {get x() {return this.a + this.b}, b: 2, ...a && {a}} works as expectedMyrtismyrtle
@zb' { ...{ get x() { return 3 } } }Cliftonclim
@RyanKing ah, optional getter ;) o'c you can't destruct getter ;)Myrtismyrtle
I receive an error in the false value, I solved with this: ...(flag2 && { optionalKey2: 6, optionalKey3: 7 }) as {},Miguelinamiguelita
sos un capo man.Incompletion
lol. Mucho gracias amigo.Pogue
@Abdull - thanks for the edit. I made updates, and mentioned you in a comment.Pogue
R
3

To indicate optional key, you can assign to it null, if the condition is false

const someCondition = true;

const obj = { 
  requiredKey1: 1, 
  requiredKey2: 2,
  optionalKey1: someCondition ? 'optional' : null
};

console.log(obj);
Remediless answered 19/12, 2017 at 17:21 Comment(5)
Good answer, but worth noting that by doing this, optionalKey1 still appears as one of the keys of the object if the condition is false (and has the value null), whereas OPs original snippet will create an object that lacks the key entirely if the condition is false.Carder
I think, assigning null to the property is more understandable that it is optional and does not have value than checking for the existenceRemediless
I personalyl would like to get some sort of error, and generally whatever behavior a language (and JavaScript in particular) would give me when trying to access an inexistent property, rather than making it nullable, since it's not ever going to have a value, unlike what nullable values are used for - it it needs to exists, it exists. If it doesn't need to exits, it doesn't - I think that makes more sense.Chalco
@SurenSrapyan adding an optional member with null value doesn't make it optional. It means that the object has an actual member whose assigned value is null which actually is a value. You may thing that null is not a value, but it is. Therefore this doesn't make a member optional. An optional member would be one, that wouldn't be returned by the Object.entries(obj) function. If at least you'd assign it a value of undefined which would mean that the member is undefined and doesn't have a value assigned to it. Object.entries(obj) would still see the member though.Woolridge
One workaround to fix the optional member with null would be removing it in the next line: Object.keys(obj).forEach((k) => obj[k] == null && delete obj[k]); @SurenSrapyan If you add this line, that will make this answer also one of the options.Berberidaceous
C
-1

You can declare the variable by passing it through the below function

function removeOptionalKeys(x){
    let obj = {};
    Object.keys(x).forEach((a) => {
        if(x[a]){
            obj[a] = x[a]   
        }
    })
    return(obj)
}

Then declare the variable as follows

let obj = removeOptionalKeys({
  requiredKey1: 1, 
  requiredKey2: 2,
  optionalKey1: someCondition ? 'optional' : null  
})
Cozmo answered 21/12, 2023 at 7:3 Comment(1)
That removes all properties with falsy values, which is probably not desiredThormora
T
-4

the following pattern is common in Javascript

It should not. Having many objects of different shapes can incur a performance penalty. Records should always contain the same keys. So just use

const obj = { 
  requiredKey1: …, 
  requiredKey2: …,
  optionalKey1: someCondition ? … : undefined,
};
Thormora answered 20/12, 2017 at 19:57 Comment(2)
The pattern is really useful in objects you pass as options.Kongo
@Kongo Option object parameters usually can deal totally fine with undefined properties, not distinguishing them from non-existing properties.Thormora

© 2022 - 2024 — McMap. All rights reserved.