typing: ref of type A | undefined do not unwrap refs in A
Version
3.0.4
Reproduction link
https://codesandbox.io/s/goofy-sinoussi-gojxu?file=/src/index.ts
Steps to reproduce
const r = ref<{ a: Ref<number> } | undefined>({ a: ref(3) });
r.value.a // should be type `number`, but shown as `Ref<number>`
What is expected?
r.value.a
should be type number
What is actually happening?
r.value.a
is shown as Ref<number>
instead.
It is because of the override function.
export function ref<T extends object>(value: T): ToRef<T>
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
your code const x = ref<{ a: Ref<number> } | undefined>();
will run as ref<T = any>(): Ref<T | undefined>
. The T
type doesn't include in the UnwrapRef.
So, the export function ref<T = any>(): Ref<T | undefined>
should be export function ref<T = any>(): Ref<UnwrapRef<T> | undefined>
.
But while changing export function ref<T = any>(): Ref<T | undefined>
to export function ref<T = any>(): Ref<UnwrapRef<T> | undefined>
, ref's setter shows the error setting type.
const x = ref<{ a: Ref<number> } | undefined>();
// ERROR Type 'Ref<number>' is not assignable to type 'number'.ts(2322)
x.value = { a: ref(1) };
Make sense. Thanks you @Zcating.
I find it slightly hard to work with the typing when we have nested refs.
For example, this will cause the type go wrong
const useA = () => ({
a: ref(3),
});
const x = ref(useA());
x.value = useA(); // you can't do this coz x is not `Ref<{ a: number }>`
It is because the getter & setter must be the same type. If change ref.value
to ref.setValue & ref.getValue
, you can do this:
setValue(value: T);
getValue(): UnwarpRef<T>;