Composition-api: computed shouldn't return readonly

Created on 11 Dec 2019  路  3Comments  路  Source: vuejs/composition-api

const test = computed(() => {
    return { asdf: 5 };
});
test.value.asdf = 6;

Currently the return type for computed is Readonly<Ref<Readonly<T>>>, so last line gives me an error saying that "asdf" is a read-only property.

It should be just Readonly<Ref<T>> so that the "value" isn't writable, but there's no reason for the actual object it returns to be readonly, it should give me exactly what i return from the computed function and whether i want it to be readonly or not should be my problem.

Most helpful comment

It seems to be supported in vue-next though? https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/computed.ts

I don't see why the api should change the object I'm returning in any way.
It obviously doesn't make sense in the example i posted, but my actual use case is returning a reactive object from some reactive store state and i'm using the computed as a cached shortcut so i don't have to search the store every time. I think calling that a hack is a stretch.

I guess I'll just stick with v0.3.2 where this works for now and wait for vue3.

All 3 comments

This is working as expected, you shouldn't modify a computed property, doing otherwise would be a hack and if you want, you can get around the typing error by using a @ts-ignore

It seems to be supported in vue-next though? https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/computed.ts

I don't see why the api should change the object I'm returning in any way.
It obviously doesn't make sense in the example i posted, but my actual use case is returning a reactive object from some reactive store state and i'm using the computed as a cached shortcut so i don't have to search the store every time. I think calling that a hack is a stretch.

I guess I'll just stick with v0.3.2 where this works for now and wait for vue3.

I have another use case in which the Readonly type seems to be a problem.

In my case, I have a computed property that returns a callback, but I cannot call it because it's declared as Readonly. Here is an example:

const propertyGetter = computed(() => {
    // Property value is a callback that takes an object
    // and access to a property of that object
    return (object: any) => object[props.propertyName];
});

const myTestObject = { /* ... */ };
propertyGetter.value(myTestObject);

The last line throws the following error:

TS2349: This expression is not callable.
Type 'Readonly<(object: any) => any>' has no call signatures.

I had to do a cast in order to avoid the error:

const propertyGetter = computed(() => {
    // Property value is a callback that takes an object
    // and access to a property of that object
    return (object: any) => object[props.propertyName];
}) as Readonly<Ref<(object: any) => any>>;

It can be done using an utility function as well:

function asWriteableComputed<T>(
        computedProperty: Readonly<Ref<Readonly<T>>>
): Readonly<Ref<T>> {
    return computedProperty;
}

const propertyGetter = asWritableComputed(computed(() => {
    // Property value is a callback that takes an object
    // and access to a property of that object
    return (object: any) => object[props.propertyName];
}));

Having to do this seems a little tricky. It would be great if computed() returned a Readonly<Ref<T>> instead :)

Was this page helpful?
0 / 5 - 0 ratings