`toRaw` has wrong typing for `DeepReadonly` array
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[]
*.
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.
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?
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[]'.