Subscribe on changes!

Type of ref for Map with generic in values is abnormal.

avatar
Dec 7th 2023

Vue version

3.3.10

Link to minimal reproduction

https://play.vuejs.org/#eNp9U8lu2zAQ/ZUBL5EBV0aSmyob6OJDA6QtGvdk+aBKY5uJRBJcFAeG/r1DUrYVJIgNSZztzZuFR/ZFqbRzyDKWm0pzZcGgdQqaUuzmBbOmYItC8FZJbeEIGrfTSrbKWayhh62WLVxR/NXnQhTCviiEvwY1zOFYCABeZyBc+w/11IuibDEDYzUXu0L0PmTrRGW5FOAMPtjSYr5aJJMYXUlhLKUsyaPD+1IRLBFIBD4DSfmADD5iQgROEQ2n15yEyDNfrTeLhEDnizFuqXUGZCLP9SZEA6zTNB3lS7uycZg+4YtJJpt0K/WyrPYJyWcs/yOkVDmzT96G7tB698kk+vbDV1OPtfCBIXFU+2cwDNAjvNA/CKWFiNC+WIifysUvVt9TVeeO+olQi8KI3lKkeSfX08u8rkejKtjdXgqE7xILRik9xvsINyOEm1cIv/e84Qrupea0TANI/OezuHO0YSRYbFVDfEkCyGvehQP4OrTJ4tmroftEk6Dl9AbgIjaFQUaNHrQpr8PexvkcjwEj9Yygp74FpNklQ0g4yPnszINNaf+px1u+Sx+NFHRJQo0F86vFG9S/lN9dKis7jaxgZdPI57ugs9rhMDiK2WP19I7+0Ry8jhqlkVh21OmzzZaaNiialw8/8UDns7GVtWvI+wPjHzSycZ5jdPvqRE20R36B7Y9wvelSrszyYFGYU1GeaFi34F8wuunfPij9Qvc2vT2tKev/Ay/CctU=

Steps to reproduce

  1. Create ref with Map that use generic
const reactiveMap = ref(new Map<number, T>());
  1. Try to assign value from crated map in other place that expect this generic:
const test: T = reactiveMap.value.get(1)

You can check typescript error on line 14 in App.vue file in reproduction link.

What is expected?

Code works without any typescript errors.

What is actually happening?

Got error:

 Argument of type 'UnwrapRefSimple<T>[]' is not assignable to parameter of type 'T[]'.
  Type 'UnwrapRefSimple<T>' is not assignable to type 'T'.
    'T' could be instantiated with an arbitrary type which could be unrelated to 'UnwrapRefSimple<T>'

System Info

No response

Any additional comments?

This issue happens on 3.3.10 versions and works well on 3.3.9 I may assume that issue related to this changes: https://github.com/vuejs/core/pull/8960/files#diff-81475b10580b705fb8421b8c430ac63220938646c0e09141be79c85b0ea392ffR499 that was included in lates release.

avatar
Dec 7th 2023

Values of object types are recursively unwrapped. Due to TypeScriptinability to recognize whether the values in your generic type include the Ref type, it recursively unwraps the values of the object. As a result, an UnwrapRefSimple<T> type is obtained. You can try handling this issue as follows:

  const reactiveMap: Ref<Map<number, T>> = ref(new Map());
  const arr: T[] = []
  arr.push(reactiveMap.value.get(1)) // T
avatar
Dec 7th 2023

Thanks for the answer. Yeah, i know that i can workaround this issue by using typecast. The your version or like this: const reactiveMap = ref(new Map()) as Ref<Map<number, T>>;

But my point that previously it was worked correct and doesn't required any additional actions in the code. And latest changes bring this side effect so it looks like regression.

This is why i decided to report this issue.

avatar
Dec 7th 2023

@sinkersan the current type is correct, @Alfred-Skyblue is correct on the explanation.

the same issue is/was present since a long time ago:

function test<T>(): Ref<T> {
  const r = ref<T>(null)
  return r;
}

image

The solution is, if you're sure T is not a ref you need to cast it

 const r = ref<T>(null) as Ref<T>

Just bear in mind that the type might not be exactly the same, because of the unwrapping.
The reason before was working was because of the type issue where collections were being ignored, but it was fixed recently and not a regression.