Search code examples
vue.jsvuejs3

Exclude keys from Vue readonly object protection


I can make the object passed to the Vue 3 readonly() function read-only. Is there a way to make the object read-only except for the obj.target key or other specified keys?

import { reactive, readonly } from 'vue'

const obj = reactive({
  name: 'example',
  target: 'DOM',
})

const readonlyObj = readonly(obj)
readonlyObj.target = 'Modal' // not writable by default

Is there a way to allow editing of certain keys (as target) in a readonly object or not?


Solution

  • This means that the object needs to be composed in a way that makes it possible to modified the original writable property through obj.target.

    If it's impractical to keep a reference to the whole obj for some reason, there needs to be a reference to target at least, e.g.:

    // Private
    const obj = reactive({
      name: 'example',
      target: 'DOM',
    })
    
    // Public
    const readonlyObj = readonly(obj)
    const targetRef = toRef(obj , 'target')
    targetRef.value = 'Modal'
    

    Otherwise a completely new alternative to readonly needs to be created. E.g. a high-level approach that is limited to existing keys, similarly to reactivity requirements in Vue 2:

    const semiReadonly(obj, readonlyKeys) {
      let newObj = {};
      for (const key of Object.keys(obj)) {
        if (readonlyKeys.includes(key))
          newObj[key] = computed(() => obj[key]);
        else
          newObj[key] = computed({
            get(key) {
              return obj[key];
            },
            set(key, val) {
              obj[key] = val;
            }
          });
      }
      
      return reactive(newObj);
    }
    

    In order to support changing set of keys it would require a watcher, or be implemented with low-level approach that uses Proxy.