This is a small quality-of-life improvement.
Many libs and composables will accept potentially reactive inputs.
They will typically read those input by doing unref(x), which works on both plain values and refs.
So the following typing might become a common pattern:
// Typing
function useLength(input: string | Ref<string>): Ref<number>;
// Example uses
let s1 = "abc";
let l1 = useLength(s1);
let s2 = ref("123");
let l2 = useLength(s2);
I think it would be convenient and set a common standard for everyone if Vue exported the following type (name up for bikeshedding):
export type RValue<T> = T | Ref<T>
Of course, everybody is free to declare such a type in userland.
I think it might be convenient to import it from "vue", which is an existing import in the source files; and it would give a common name to such inputs that every lib can use (familiarity for users).
It will also encourage library authors to accept RValue<T> inputs, rather than say, Ref<T>.
That's something I do quite a lot, as you said it can be done quite easily on userland.
My only concern here is the naming RValue, I don't think RValue is good enough name to be exported from the library.
I personally call them MaybeRef<T> in my codebases, as the argument may be a Ref, or not 馃檭
They will typically read those input by doing unref(x)
All my usages of MaybeRef (so far 1 xd) are actually getting T | ComputedRef<T> since I use this values only for reading - it makes me think that T | ComputedRef<T> is actually a better idea.
Is there even a usecase when I would want to pass T | Ref<T> and have possibility of updating the value of ref?
Is there even a usecase when I would want to pass T | Ref
and have possibility of updating the value of ref?
I'd say there surely are usecases even though they might not be that many. But since Ref also matches for computed refs, it just is more convenient: People can pass a ref or computed ref, whichever they have at hand when calling your composable.
@jacekkarczmarczyk
since I use this values only for reading
Computed has is not about reading, it can be read/write, too.
It's a ref that uses computations rather than being a plain value itself: think get/set property instead of field.
What you're saying is that a readonly ref might make more sense: T | readonly Ref<T>.
I'm not sure if that typing works but I agree 100% with you.
Since T can't be written to, I wouldn't expect the code to write to the ref either.
A MaybeRef should accept any kind of ref, including readonly refs: ref(1), computed(() => 1), readonly(ref(1)).
I'd say there surely are usecases even though they might not be that many.
There's always corner cases, but then one can use something else than MaybeRef<T> for typing.
I see this type as a convenience and "standard" for the common case.
Computed has is not about reading, it can be read/write, too.
Well, not in this case:

Anyway you're right, I had readonly in mind, if you think that readonly Ref<T> is better than ComputedRef<T> then let it be, can I get an explanation though how would writing to ComputedRef be possible given the above example?
There's always corner cases, but then one can use something else than MaybeRef
for typing.
+1
What I meant is that -- as far as concepts go -- you can create writable computeds:
let x = computed({ get: ..., set: ... })
It looks like the type ComputedRef<T> is meant for the getter-only version.
Makes sense since a writable computed is exactly like Ref from the type-system perspective.
Then again the readonly computed is exactly like a readonly ref for the type-system, so now I'm a bit lost in the way the types are organized. 馃樀
No matter what the actual types are, I think the goal is this:
A MaybeRef should accept [...]: ref(1), computed(() => 1), readonly(ref(1)).
Plus plain T of course and you should be able to call unref on it.
A MaybeRef should accept [...]: ref(1), computed(() => 1), readonly(ref(1)).
Plus plain T of course and you should be able to call unref on it.
If we agree on MaybeRef being readonly then it should be added to the above requirements. I'm not sure if it's a bug in vue typings or limitations of TS, but you can pass a readonly ref (or computed ref) to a function that accepts writable refs:
function t (x: Ref<number>) {
x.value = 1;
}
t(computed(() => 1)); // should not be allowed
Most helpful comment
I personally call them
MaybeRef<T>in my codebases, as the argument may be aRef, or not 馃檭