Просмотр исходного кода

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

Evan You 4 лет назад
Родитель
Сommit
2db9c909c2
3 измененных файлов с 41 добавлено и 3 удалено
  1. 12 0
      packages/reactivity/__tests__/ref.spec.ts
  2. 22 3
      packages/reactivity/src/ref.ts
  3. 7 0
      test-dts/ref.test-d.ts

+ 12 - 0
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,

+ 22 - 3
packages/reactivity/src/ref.ts

@@ -206,10 +206,15 @@ export function toRefs<T extends object>(object: T): ToRefs<T> {
 class ObjectRefImpl<T extends object, K extends keyof T> {
   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> = [T] extends [Ref] ? T : Ref<T>
 export function toRef<T extends object, K extends keyof T>(
   object: T,
   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]> {
   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

+ 7 - 0
test-dts/ref.test-d.ts

@@ -224,6 +224,13 @@ expectType<Ref<string>>(p2.obj.k)
   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
 interface AppData {
   state: 'state1' | 'state2' | 'state3'