'Why is there an "unexpected mutation of prop" when this is not a prop?

This code below triggers an error for the <q-input> component

 ESLint: Unexpected mutation of "serviceName" prop. (vue/no-mutating-props)

The thing I do not understand is why serviceName is seen as a prop when I explicitly crated the reference from the prop.

Does this mean that changes in serviceName will bubble to props? If so does this mean that I have to copy the contents of props into a new reactive variable, breaking the relationship with the prop?

<template>
  <div class="q-pa-md">
    <q-form
    @submit="true"
    >
      <div class="row q-gutter-md">
        <q-input v-model="serviceName" label="service" class="" filled></q-input>
      </div>
      <div class="row q-gutter-md">
        <q-input v-model="serviceConf.image" label="image"></q-input>
        <q-input v-model="serviceConf.container_name" label="container_name"></q-input>
      </div>
    </q-form>
  </div>
</template>

<script lang="ts">
export default {
  name: 'EditService'
}
</script>

<script lang="ts" setup>
import { toRef, PropType } from 'vue'
import { ServiceFull } from 'components/defs'

const props = defineProps({
  serviceName: {
    type: String
  },
  serviceConf: {
    type: Object as PropType<ServiceFull>
  }
})
const serviceName = toRef(props, 'serviceName')
const serviceConf = toRef(props, 'serviceConf') as unknown as ServiceFull

</script>

For reference, ServiceFull is defined as

// name of the service
export type ServiceName = string
// description of the service below the name
export interface ServiceConfig {
  container_name: string
  image: string
  environment: string[]
  restart: string
  volumes: string[]
  ports: string[]
  depends_on: string[]
  cap_add: string[]
}
// complete service, name + config → used to transfer between components
export interface ServiceFull {
  name: ServiceName
  conf: ServiceConfig
}


Solution 1:[1]

The docs explain that toRef keeps a reactive connection to the source property, so modifying the resulting ref would update the original property. In addition to the linter warning, you'd see a browser console warning when trying to use this ref in a v-model:

Set operation on key "serviceName" failed: target is readonly.

To be able to modify serviceName independently from the prop, you could use a ref of the prop value (i.e., a copy):

import { ref } from 'vue'
const serviceName = ref(props.serviceName)

demo

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tony19