30

I have stumbled on a weird issue when trying to recursively set properties on an empty object with the following code:

Simplified code

const birthdays = {};

// Loop -> Passing day, id and birthday
birthdays[day] = day;
birthdays[day][id] = birthday;

Example of day: '01012017'

Example of id: 1547

Example of birthday: {name: John}

Error message

Cannot create property '123' on string '06012017'

I saw some people with Angular having this issue but their answer don't solve anything for me (as is angular specific syntax etc).

NealVDV
  • 2,302
  • 3
  • 26
  • 51
  • 2
    The error seems pretty clear. What is your question? – Felix Kling Jan 06 '17 at 16:47
  • 1
    @FelixKling I was messing up the init of `birthdays[day]` with the day itself, using the `birthdays[day] = {}` fixed it for me. – NealVDV Jan 06 '17 at 16:49
  • There's no error in that code. It's perfectly valid Javascript. You can do this: `birthdays['01012017'] = '01012017'` and then this `birthdays['01012017'][1547] = {name: 'John'}`, and it will NOT trigger any such error. – GetFree Mar 07 '21 at 00:37
  • @GetFree - that is a tricky one - but you are right because Strings allow setting (characters) by numeric index causes no error - the code is valid but you can't access that value later `birthdays['01012017'][1547] === undefined` – Ian Carter Apr 07 '23 at 06:47
  • If the day value is a string `let sDay='01012017'; birthdays[sDay]=sDay;` then ⚡ `sDay.id='birthday'` causes the TypeError as scalar system types (String, Number, Boolean,...) in general are "frozen" (can not have any new props assigned). `Object.isFrozen('01012017') === true`. To avoid this but keep the "string" feeling - a wrapper class could be used: `class Value{constructor(v){this.value=v;}toString(){return this.value;}}` making `birthdays[day]=new Value(day);birthdays[day][1547]={name:"John"}` is error free and `birthdays[day]` has props and `String(birthdays[day]) === '01012017'` – Ian Carter Apr 07 '23 at 06:55

3 Answers3

30

Empty Objects need to be individually created before their values are assigned. And use of const is not a good idea here, anyway, it's just my suggestion.

const birthdays = {};
var day = 123;
var id = 21;
var birthday = 2016;
// Loop -> Passing day, id and birthday
birthdays[day] = {};
birthdays[day][id] = birthday;
Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
  • 1
    It solved my issue! I was messing up the init of `birthdays[day]` with the day itself, using the `birthdays[day] = {}` totally worked – NealVDV Jan 06 '17 at 16:46
  • 3
    Use of const is perfectly fine and best practice here. It means that you are not going to reassign a variable. Don't be confused with immutability of value – Сергей Гринько Dec 01 '22 at 23:55
6

I had a similar error message TypeError: Cannot create property 'false' on boolean 'false' in Node 14.3.0 (ES 2019), using the new Javascript semicolon-less syntax, with a variable declaration and assignment followed by a destructuring assignment on the next line.

The code that caused the error:

var a = b ()
[c, d] = e ()

Solved by:

var a = b ()
;
[c, d] = e ()
gregn3
  • 1,728
  • 2
  • 19
  • 27
0

First, define the object:

let birthdays = {};

Then, get the attributes you want to use in that object:

let day = '20210203';
let id = 77;

Afterwards, create a pair of the two attributes (bear in mind the square brackets, that's an ES6 feature to use the variable as a key):

let pair = {[id]: day};

And, finally, form up the main object like this:

birthdays = {...birthdays, ...pair};

And voila, you've added a kvp to an empty object and you won't be getting the "Cannot create property '77' on string '20210203'" error anymore.

Bullsized
  • 362
  • 4
  • 7
  • This is incorrect. Objects are not iterable so you can't use the spread syntax with them. This will trigger an error: `...birthdays`, as well as this `...pair`. – GetFree Mar 07 '21 at 00:28
  • where exactly do you see iterations, @GetFree? try all of the lines in your browser console and you will see that there is no error thrown whatsoever. – Bullsized Mar 08 '21 at 07:30
  • I did try them. The 3 dots syntax `...` requires the value to its right to be iterable. That's why this `...birthdays` will throw an error. – GetFree Mar 08 '21 at 07:43
  • 1
    @GetFree, the spread operator is valid on both an iterable and an object. You can spread the contents of an array, or spread out the key-value pairs. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax – jndietz Oct 05 '22 at 03:12