Generic array type infer incorrect
Version
3.0.0-rc.11
What is expected?
The parameter type of the push
method of the generic array should be T
not UnwrapRefSimple <T>
What is actually happening?
The parameter type is inferred to UnwrapRefSimple <T>
Steps to reproduce
Reproduce code ↓
import { reactive } from 'vue';
export interface QueueMethods<T> {
add: (item: T) => void;
}
const useQueue = <T>(initialValue: T[] = []): QueueMethods<T> => {
const queue = reactive(initialValue);
return {
add(value: T) {
queue.push(value);
},
};
};
export default useQueue;
Caused by this line ↓
https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/ref.ts#L204-L206
Why is it that the type of Ref not inherited is also using UnwrapRefSimple
to infer
When using ref or reactive with generics you need to cast to as Ref<T>
and as reactive<T>
if you sure that the type doesn't have any nested refs, because ref and reactive will unwrap nested refs automatically.
EDIT: You can test by simply doing:
const value = {
a: ref({
a : 1
})
}
value.a.value.a // 1
const reactiveValue = reactive(value)
reactiveValue.a.a // 1
const valueJson = JSON.stringify(value)
const reactiveJson = JSON.stringify(reactiveValue)
valueJson !== reactive // because the reactiveValue will unwrap `a`
which makes T !== reactive<T>
@yuxino How did you solve this problem? i have the same thing
export const usePagination = <T>({ url }: { url: string }) => {
const client = API
const index = ref<T[]>([])
const get = async (): Promise<IndexResponse<T>> => {
const { data } = await client.get<IndexResponse<T>>(`${url}`)
// Type 'T[]' is not assignable to type 'UnwrapRefSimple<T>[]'.
index.value = data.data
return data
}
return {
index,
get
}
}
@yuxino How did you solve this problem? i have the same thing
export const usePagination = <T>({ url }: { url: string }) => { const client = API const index = ref<T[]>([]) const get = async (): Promise<IndexResponse<T>> => { const { data } = await client.get<IndexResponse<T>>(`${url}`) // Type 'T[]' is not assignable to type 'UnwrapRefSimple<T>[]'. index.value = data.data return data } return { index, get } }
const index = ref<T[]>([]) as Ref<T[]>
can solve this problem
When using ref or reactive with generics you need to cast to
as Ref<T>
andas reactive<T>
if you sure that the type doesn't have any nested refs, because ref and reactive will unwrap nested refs automatically.
Using Vue 2.7, it looks like it should be as Ref<T>
for ref()
and as T
for reactive()
, rather than as Ref<T>
for ref()
and as reactive<T>
for reactive()
. I have not tested with Vue 3 yet.