Vue Computed property not updating – Strange behavior of undefined data property

For the sake of explanation, i made an example of code in a .vue single file

<template>
  <div id="app">
    <h1>{{score}} : Score with undefined minScore but declared on data</h1>
    <h1>{{score2}} : Score with undeclared/undefined minScore2</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      minScore: undefined,  
      // Uncomment minScore2 to fix weird behavior
      // minScore2: undefined
    }
  },
  computed: {
    score() {
      return this.minScore + 5
    },
     score2() {
       return this.minScore2 + 5
    }
  },
  created() {
   setTimeout(() => { 
     this.minScore = 10
     this.minScore2 = 10
}, 1000)
  }
};
</script>

We use the above component to display score as a computed property, calculating it’s value by summarizing it with the number 5.
After 1 second we try to update this.minScore and this.minScore2 using the same setTimeout() function.

The component loads, the template asks for the computed properties score and score2. Both show NaN at the beginning. After the 1 second passes, this.minScore updates it’s value correctly to the number 15, but this.minScore stucks to the previous NaN result.

The only difference is that minScore is declared as undefined explicitly and minScore2 is not. There are not any error messages in console.

My question is why in Vue you need to implicitly initialize an undefined property, when in javaScript both of the properties would be treated as undefined?

P.S. I know that javaScript’s outcome from the function `undefined + number === NaN’

You can try it on the following codepen Link for Live Codepen

Answer

You cannot add root-level reactive properties to an existing component instance: Docs.

You don’t get any error, because the code is valid (you can console.log(this.minScore) and see that the property is set), but the properties that you add to this are not reactive and the template update is not triggered.

If you need to not declare the properties upfront, there is a solution. First, make them non-root.

data(){
  return {
    unitializedProperties: {
      // here will go new properties. 
    }
  }
}

Then use the set() method to add new non-root reactive props.

 this.$set(this.unitializedProperties, 'minScore', 10)

You can view it in action in your edited codepen