Subscribe on changes!

`toRaw` has wrong typing for `DeepReadonly` array

avatar
Jan 6th 2023

Vue version

3.2.45

Link to minimal reproduction

No need

Steps to reproduce

import {DeepReadonly, readonly, Ref, ref, toRaw} from "vue";


type TypeA = {a: string};

// Fine
const a1: Ref<TypeA>           = ref({a: "a1"});
const b1: Readonly<Ref<TypeA>> = readonly(a1);
const c1: TypeA                = toRaw(b1.value); // OK

// Not fine
const a2: Ref<TypeA[]>               = ref([{a: "a1"}, {a: "a2"}]);
const b2: DeepReadonly<Ref<TypeA[]>> = readonly(a2);
const c2: TypeA[]                    = toRaw(b2.value) /* as TypeA[] */; // TS4104 Error

What is expected?

toRaw returns TypeA[] type for c2.

What is actually happening?

TS4104: The type 'readonly { readonly a: string; }[]' is 'readonly' and cannot be assigned to the mutable type 'TypeA[]'.

System Info

OS: Windows 10
Node: 18.12.1

Any additional comments?

toRaw actually works as expected, but there is the problem with typing. It forces me to additionally use as TypeA[] *.

avatar
Jan 6th 2023

The related question: Why readonly returns such complicated type DeepReadonly<Ref<T>>/Readonly<Ref<T>>? Why not just DeepReadonly<T>/Readonly<T>?

It would be much more convenient.

avatar
Jan 6th 2023

I figure out how to fix it. I need to use readonly when I pass DeepReadonly into toRaw:

// It works
const a2: Ref<TypeA[]>               = ref([{a: "a1"}, {a: "a2"}]);
const b2: DeepReadonly<Ref<TypeA[]>> = readonly(a2);
const c2: readonly TypeA[]           = toRaw(b2.value);

Is it planned behavior?

avatar
Jan 6th 2023

However, readonly type modifier is only permitted on array and tuple literal types. (TS1354)

In this case there is a problem anyway:

class A {
    // get selves(): [A] { // same thing
    //     return [this];
    // }
    children: A[]
}

const a: Ref<A>               = ref(new A());
const b: DeepReadonly<Ref<A>> = readonly(a);
const c: A                    = toRaw(b.value); // TS2322
TS2322: Type '{ readonly children: readonly ...[]; }' is not assignable to type 'A'.
   Types of property 'children' are incompatible.
     The type 'readonly { readonly children: readonly ...[]; }[]' is 'readonly' 
     and cannot be assigned to the mutable type 'A[]'.
avatar
Jan 7th 2023

Is toRaw should not return the original type without any change?

avatar
Sep 3rd 2023
const a2: TypeA[]               = reactive([{a: "a1"}, {a: "a2"}]);
const b2: DeepReadonly<TypeA[]> = readonly(a2);
const c2: TypeA[]                = toRaw(b2) // error

got same problem, after toRaw(b2), c2 is mutable, but type is still DeepReadonly<TypeA[]>