vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
46.97k stars 8.24k forks source link

Props should be immutable as default #8794

Open AndreiSoroka opened 1 year ago

AndreiSoroka commented 1 year ago

Vue version

3.3.4

Link to minimal reproduction

https://play.vuejs.org/#eNp9Uk1vwjAM/StZLgWJUU3cWEHaJqRt0gbaJu2SS9WaEpYmUZIyUNX/PieFwtjHLfZ7sZ/tV9MbrYebCuiYJjYzXDtiwVWauJ2GCaPOMjplkpdaGUdqYiDNlRS7Ab6WpCFLo0oSYYGoI92pUu/zw9gHvn50zSSTmZLWkdIWZOL/96J7EEKRd2VEfhH1DwTfZI5NnsDatIBAbtv28G8fSyVxKxalYeCg1CJ1gBEhyepqWtehSdMkMUYhy6WuHNlclioHgYMhHiZDKAgel20zhM7aM0piJCZx14YOcC8odcmL4doqicurfSVGMyzFBZi5dhxHYXRMAuKxFEf9fAw5ZyoYHPLZCrKPX/Jru/U5RhcGLJgNCukwl5oCXAvPXp9hi+8OxBErgex/wBewSlReY0u7rWSOsk94Qe1DuCiXxZudbR1IexjKC/XMJvAZxQv7Lf41+lHuaDgK/5hscIsHd/xwn0hlcXQfkzksuYSFUdom+6r7e42JdQYVYsFp78wap8ZIcr4Jvth7ynvDp74ftvkClMQJpw==

Steps to reproduce

In the pinia I created readonly ref

image

I send props in the component

image

and in the component I get props

image

All is working, but type-check send:

 error TS4104: The type 'readonly ({ readonly id: string;} | { ...; } | { ...; })[]' is 'readonly' and cannot be assigned to the mutable type 'Item[]'.

What is expected?

props shouldn't be mutable

https://vuejs.org/guide/components/props.html#one-way-data-flow

What is actually happening?

props are mutable

System Info

System:
    OS: macOS 14.0
    CPU: (10) arm64 Apple M1 Pro
    Memory: 87.11 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.3.0 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.6.7 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 114.0.5735.198
    Safari: 17.0
  npmPackages:
    vue: ^3.3.4 => 3.3.4

Any additional comments?

I can wrap Readonly, but I think it is overhead for each props

P.s. And I catch errors in some libs https://github.com/anish2690/vue-draggable-next/issues/56 who is using it

Shyam-Chen commented 1 year ago

I am using it.

https://github.com/Shyam-Chen/Vue-Starter/blob/main/src/components/Transfer.vue

Shyam-Chen commented 1 year ago
- const readOnlyMessage = readonly(msg);
+ const readOnlyMessage = msg.value;
import { toRaw } from 'vue';
structuredClone(toRaw(items));
<script type="ts" setup>
import { reactive, readonly, watchEffect } from 'vue';

const original = reactive({ count: 0 });

const copy = readonly(original);

watchEffect(() => {
  // works for reactivity tracking
  console.log(copy.count);
});

// mutating original will trigger watchers relying on the copy
original.count += 1;

// mutating the copy will fail and result in a warning
// copy.count += 1; // warning!
</script>

<template>
  <pre>{{ original }}</pre>
  <pre>{{ copy }}</pre>
</template>
AndreiSoroka commented 1 year ago

const readOnlyMessage = msg.value;

@Shyam-Chen my purpose is to make both reactive and readonly property

For example:

// not working, but expected
defineProperties<{
  message: string,
}>()

// working, but overhead for each property
defineProperties<{
  message: Readonly<string>,
}>()