typescriptvuejs3immutabilityvue-props

How to prevent the mutation of nested prop fields in Vue 3, using TypeScript?


Suppose I have the following SFC component:

<script setup lang="ts">
export interface Person {
  name: string;
}

const props = defineProps<{
  person: Person;
}>();

function onClick(): void {
  props.person.name = 'Joe'; // mutate nested field
}
</script>

<template>
  <button @click="onClick">Click</button>
</template>

How can I prevent the mutation of the nested prop field?


Solution

  • you can use the readonly modifier to make the props readonly. This will ensure that the props cannot be mutated within the component.

    <script setup lang="ts">
    export interface Person {
      name: string;
      address: {
        city: string;
        street: string;
      };
    }
    
    type DeepReadonly<T> = {
      readonly [K in keyof T]: DeepReadonly<T[K]>;
    };
    
    const props = defineProps<{
      person: DeepReadonly<Person>;
    }>();
    
    function onClick(): void {
      // TypeScript error: Cannot assign to 'name' because it is a read-only property
      props.person.name = 'Joe';
    
      // TypeScript error: Cannot assign to 'city' because it is a read-only property
      props.person.address.city = 'New City';
    }
    </script>
    
    <template>
      <button @click="onClick">Click</button>
    </template>