feat(reactivity): support default value in toRef()

This commit is contained in:
Evan You 2021-12-11 16:41:58 +08:00
parent d0ea900922
commit 2db9c909c2
3 changed files with 41 additions and 3 deletions

View File

@ -269,6 +269,18 @@ describe('reactivity/ref', () => {
expect(toRef(r, 'x')).toBe(r.x) expect(toRef(r, 'x')).toBe(r.x)
}) })
test('toRef default value', () => {
const a: { x: number | undefined } = { x: undefined }
const x = toRef(a, 'x', 1)
expect(x.value).toBe(1)
a.x = 2
expect(x.value).toBe(2)
a.x = undefined
expect(x.value).toBe(1)
})
test('toRefs', () => { test('toRefs', () => {
const a = reactive({ const a = reactive({
x: 1, x: 1,

View File

@ -206,10 +206,15 @@ export function toRefs<T extends object>(object: T): ToRefs<T> {
class ObjectRefImpl<T extends object, K extends keyof T> { class ObjectRefImpl<T extends object, K extends keyof T> {
public readonly __v_isRef = true public readonly __v_isRef = true
constructor(private readonly _object: T, private readonly _key: K) {} constructor(
private readonly _object: T,
private readonly _key: K,
private readonly _defaultValue?: T[K]
) {}
get value() { get value() {
return this._object[this._key] const val = this._object[this._key]
return val === undefined ? (this._defaultValue as T[K]) : val
} }
set value(newVal) { set value(newVal) {
@ -222,9 +227,23 @@ export type ToRef<T> = [T] extends [Ref] ? T : Ref<T>
export function toRef<T extends object, K extends keyof T>( export function toRef<T extends object, K extends keyof T>(
object: T, object: T,
key: K key: K
): ToRef<T[K]>
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue: T[K]
): ToRef<Exclude<T[K], undefined>>
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue?: T[K]
): ToRef<T[K]> { ): ToRef<T[K]> {
const val = object[key] const val = object[key]
return isRef(val) ? val : (new ObjectRefImpl(object, key) as any) return isRef(val)
? val
: (new ObjectRefImpl(object, key, defaultValue) as any)
} }
// corner case when use narrows type // corner case when use narrows type

View File

@ -224,6 +224,13 @@ expectType<Ref<string>>(p2.obj.k)
expectType<Ref<number>>(toRefsResult.a.value.b) expectType<Ref<number>>(toRefsResult.a.value.b)
} }
// toRef default value
{
const obj: { x?: number } = {}
const x = toRef(obj, 'x', 1)
expectType<Ref<number>>(x)
}
// #2687 // #2687
interface AppData { interface AppData {
state: 'state1' | 'state2' | 'state3' state: 'state1' | 'state2' | 'state3'