Perserve immutable semantic on accessing reactive object properties
What problem does this feature solve?
The Problem:
readonly()
immutable semantic silently lost on accessing :
// ex. 1
const x = ref(0)
const o = reactive({
x: readonly(x),
//.. other mutable props ..
})
++o.x // 1 ( =mutable )
We may use no-setter computed()
instead but intention is less obvious :
// ex. 2
const x = ref(0)
const o = reactive({
x : computed( () => x.value )
// .. other mutable props ..
})
++o.x // warnings: Write operation failed: computed value is readonly
Feature request:
Vue should preserve immutable semantic when users assign a readonly()
ref to a reactive property ( ex.1 ) ; and show warnings when immutable reactive properties are being mutated ( as if ex.2 ) .
End user experience:
When we receive a object wrapped in reactive()
from "parent component" ( or "inject from provider" or "Pinia store instance" )
we're now confident to mutate any properties as data providers are now able-to and supposed-to handle access control for all data they provided in the single reactive/ref.
With Volar, we can even get early errors.
// ex. consume a Pinia store, mutate a readonly ref immutWallet
import useMyStore from './stores/myStore.js'
const store = useMyStore() //-> a reactive
const onClick = () => ++store.immutWallet // Volar: Error: key 'immutWallet' is readonly.
This feature may immediately solve https://github.com/posva/pinia/issues/872#issuecomment-986019356
What does the proposed API look like?
Code sample
Data providers setup access control for properties
const t = ref(0) // global time for ex.
const el = ref() // in-tmpl ref for ex.
onMounted(() =>
provide( 'o', reactive({
t: readonly(t),
el
}) )
)
setInterval(() => ++t.value, 1000)
Data consumers try to access an immutable property
const o = inject( 'o' )
const onClick = () => {
o.el.dataset.triggerAt = o.t // get... ok
o.t = 0 // set... will warn in web console
}