diff --git a/packages/reactivity/__tests__/ref.spec.ts b/packages/reactivity/__tests__/ref.spec.ts index 0abe05ce..0db801a5 100644 --- a/packages/reactivity/__tests__/ref.spec.ts +++ b/packages/reactivity/__tests__/ref.spec.ts @@ -269,6 +269,18 @@ describe('reactivity/ref', () => { 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', () => { const a = reactive({ x: 1, diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 3e00541c..66c3dd43 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -206,10 +206,15 @@ export function toRefs(object: T): ToRefs { class ObjectRefImpl { 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() { - return this._object[this._key] + const val = this._object[this._key] + return val === undefined ? (this._defaultValue as T[K]) : val } set value(newVal) { @@ -222,9 +227,23 @@ export type ToRef = [T] extends [Ref] ? T : Ref export function toRef( object: T, key: K +): ToRef + +export function toRef( + object: T, + key: K, + defaultValue: T[K] +): ToRef> + +export function toRef( + object: T, + key: K, + defaultValue?: T[K] ): ToRef { 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 diff --git a/test-dts/ref.test-d.ts b/test-dts/ref.test-d.ts index 5b5274c9..f91d6415 100644 --- a/test-dts/ref.test-d.ts +++ b/test-dts/ref.test-d.ts @@ -224,6 +224,13 @@ expectType>(p2.obj.k) expectType>(toRefsResult.a.value.b) } +// toRef default value +{ + const obj: { x?: number } = {} + const x = toRef(obj, 'x', 1) + expectType>(x) +} + // #2687 interface AppData { state: 'state1' | 'state2' | 'state3'