110

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?

Ori Drori
  • 183,571
  • 29
  • 224
  • 209
Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
  • Why not just use a ternary? `optionKey1: someCondition ? value : undefined`? – Andrew Li Dec 19 '17 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. – Andrew Mao Dec 20 '17 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. – Felix Kling Dec 20 '17 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! – Andrew Mao Dec 20 '17 at 18:55
  • 4
    I would love to see something like `{ key?: optionalValue }` or with property shorthand: `{ optionalValue? }` – cimak Nov 14 '20 at 23:31

3 Answers3

292

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);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
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);
Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112
  • 26
    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. – CRice Dec 19 '17 at 17:32
  • I think, assigning `null` to the property is more understandable that it is optional and does not have value than checking for the existence – Suren Srapyan Dec 19 '17 at 17:53
  • 1
    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. – Gal Grünfeld Dec 01 '20 at 18:39
  • @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. – Robert Koritnik Aug 08 '22 at 14:20
-3

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,
};
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • The pattern is really useful in objects you pass as options. – krulik Dec 10 '19 at 10:24
  • 2
    @krulik Option object parameters usually can deal totally fine with `undefined` properties, not distinguishing them from non-existing properties. – Bergi Dec 10 '19 at 11:56