122

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?

5
  • Why not just use a ternary? optionKey1: someCondition ? value : undefined? Commented Dec 19, 2017 at 17:21
  • @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. Commented Dec 20, 2017 at 18:49
  • 1
    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. Commented Dec 20, 2017 at 18:53
  • 1
    @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! Commented Dec 20, 2017 at 18:55
  • 4
    I would love to see something like { key?: optionalValue } or with property shorthand: { optionalValue? } Commented Nov 14, 2020 at 23:31

4 Answers 4

325

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);

Sign up to request clarification or add additional context in comments.

10 Comments

Note: this will make turn any getters into static values.
As a note, you don't need the parentheses. eg. ...flag1 && { optionalKey1: 5 }, is fine too.
@RyanKing ah, optional getter ;) o'c you can't destruct getter ;)
I receive an error in the false value, I solved with this: ...(flag2 && { optionalKey2: 6, optionalKey3: 7 }) as {},
@Abdull - thanks for the edit. I made updates, and mentioned you in a comment.
|
4

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);

5 Comments

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.
I think, assigning null to the property is more understandable that it is optional and does not have value than checking for the existence
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.
@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.
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.
-2

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  
})

1 Comment

That removes all properties with falsy values, which is probably not desired
-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,
};

2 Comments

The pattern is really useful in objects you pass as options.
@krulik Option object parameters usually can deal totally fine with undefined properties, not distinguishing them from non-existing properties.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.