]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
types: improve value unwrapping
authorEvan You <yyx990803@gmail.com>
Thu, 30 May 2019 05:35:50 +0000 (13:35 +0800)
committerEvan You <yyx990803@gmail.com>
Thu, 30 May 2019 05:35:50 +0000 (13:35 +0800)
packages/observer/__tests__/value.spec.ts
packages/observer/src/effect.ts
packages/observer/src/index.ts
packages/observer/src/value.ts
packages/runtime-core/src/component.ts

index fc49e8c3bdbdcceca5bad9d43449339ee3275f3e..2e46dfcb61f07733626cb4c307b65399046fde3d 100644 (file)
@@ -38,17 +38,28 @@ describe('observer/value', () => {
     const obj = observable({
       a,
       b: {
-        c: a
+        c: a,
+        d: [a]
       }
     })
-    let dummy
+    let dummy1
+    let dummy2
+    let dummy3
     effect(() => {
-      dummy = obj.a
+      dummy1 = obj.a
+      dummy2 = obj.b.c
+      dummy3 = obj.b.d[0]
     })
-    expect(dummy).toBe(1)
+    expect(dummy1).toBe(1)
+    expect(dummy2).toBe(1)
+    expect(dummy3).toBe(1)
     a.value++
-    expect(dummy).toBe(2)
+    expect(dummy1).toBe(2)
+    expect(dummy2).toBe(2)
+    expect(dummy3).toBe(2)
     obj.a++
-    expect(dummy).toBe(3)
+    expect(dummy1).toBe(3)
+    expect(dummy2).toBe(3)
+    expect(dummy3).toBe(3)
   })
 })
index 37de5815c1ed785cd16f4e48b0415ef03277cbb1..819d7e6a361316b88cc01118ff3353f74348d683 100644 (file)
@@ -73,7 +73,7 @@ export function cleanup(effect: ReactiveEffect) {
   for (let i = 0; i < effect.deps.length; i++) {
     effect.deps[i].delete(effect)
   }
-  effect.deps = []
+  effect.deps.length = 0
 }
 
 export function track(
index 44669a79821ae028bc13a5d7eefbe536c6f73f41..0e8781ebd4faf190ced864f5e71ddd68062b2a73 100644 (file)
@@ -24,13 +24,13 @@ import {
   DebuggerEvent
 } from './effect'
 
-import { UnwrapValues } from './value'
+import { UnwrapValue } from './value'
 
 export { ReactiveEffect, ReactiveEffectOptions, DebuggerEvent }
 export { OperationTypes } from './operations'
 export { computed, ComputedValue } from './computed'
 export { lock, unlock } from './lock'
-export { value, isValue, Value, UnwrapValues } from './value'
+export { value, isValue, Value, UnwrapValue } from './value'
 
 const collectionTypes: Set<any> = new Set([Set, Map, WeakMap, WeakSet])
 const observableValueRE = /^\[object (?:Object|Array|Map|Set|WeakMap|WeakSet)\]$/
@@ -44,7 +44,7 @@ const canObserve = (value: any): boolean => {
   )
 }
 
-type ObservableFactory = <T>(target?: T) => UnwrapValues<T>
+type ObservableFactory = <T>(target?: T) => UnwrapValue<T>
 
 export const observable = ((target: any = {}): any => {
   // if trying to observe an immutable proxy, return the immutable version.
index 4101bbd35bf20866a90d48127be5dea46ccc67e8..306aab17c479af7d01c32af3132f1d7f1f9a6eb1 100644 (file)
@@ -31,58 +31,88 @@ export function isValue(v: any): v is Value<any> {
   return knownValues.has(v)
 }
 
-type UnwrapValue<T, U = T> = T extends Value<infer V> ? V : T extends {} ? U : T
-
-// A utility type that recursively unwraps value bindings nested inside an
-// observable object. Unfortunately TS cannot do recursive types, but this
-// should be enough for practical use cases...
-export type UnwrapValues<T> = {
-  [key in keyof T]: UnwrapValue<
-    T[key],
-    {
-      [k2 in keyof T[key]]: UnwrapValue<
-        T[key][k2],
-        {
-          [k3 in keyof T[key][k2]]: UnwrapValue<
-            T[key][k2][k3],
-            {
-              [k4 in keyof T[key][k2][k3]]: UnwrapValue<
-                T[key][k2][k3][k4],
-                {
-                  [k5 in keyof T[key][k2][k3][k4]]: UnwrapValue<
-                    T[key][k2][k3][k4][k5],
-                    {
-                      [k6 in keyof T[key][k2][k3][k4][k5]]: UnwrapValue<
-                        T[key][k2][k3][k4][k5][k6],
-                        {
-                          [k7 in keyof T[key][k2][k3][k4][k5][k6]]: UnwrapValue<
-                            T[key][k2][k3][k4][k5][k6][k7],
-                            {
-                              [k8 in keyof T[key][k2][k3][k4][k5][k6][k7]]: UnwrapValue<
-                                T[key][k2][k3][k4][k5][k6][k7][k8],
-                                {
-                                  [k9 in keyof T[key][k2][k3][k4][k5][k6][k7][k8]]: UnwrapValue<
-                                    T[key][k2][k3][k4][k5][k6][k7][k8][k9],
-                                    {
-                                      [k10 in keyof T[key][k2][k3][k4][k5][k6][k7][k8][k9]]: UnwrapValue<
-                                        T[key][k2][k3][k4][k5][k6][k7][k8][k9][k10]
-                                      >
-                                    }
-                                  >
-                                }
-                              >
-                            }
-                          >
-                        }
-                      >
-                    }
-                  >
-                }
-              >
-            }
-          >
-        }
-      >
-    }
-  >
-}
+type BailTypes =
+  | Function
+  | Map<any, any>
+  | Set<any>
+  | WeakMap<any, any>
+  | WeakSet<any>
+
+// Recursively unwraps nested value bindings.
+// Unfortunately TS cannot do recursive types, but this should be enough for
+// practical use cases...
+export type UnwrapValue<T> = T extends Value<infer V>
+  ? UnwrapValue2<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue2<V>>
+    : T extends BailTypes
+      ? T // bail out on types that shouldn't be unwrapped
+      : T extends object ? { [K in keyof T]: UnwrapValue2<T[K]> } : T
+
+type UnwrapValue2<T> = T extends Value<infer V>
+  ? UnwrapValue3<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue3<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue3<T[K]> } : T
+
+type UnwrapValue3<T> = T extends Value<infer V>
+  ? UnwrapValue4<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue4<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue4<T[K]> } : T
+
+type UnwrapValue4<T> = T extends Value<infer V>
+  ? UnwrapValue5<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue5<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue5<T[K]> } : T
+
+type UnwrapValue5<T> = T extends Value<infer V>
+  ? UnwrapValue6<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue6<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue6<T[K]> } : T
+
+type UnwrapValue6<T> = T extends Value<infer V>
+  ? UnwrapValue7<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue7<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue7<T[K]> } : T
+
+type UnwrapValue7<T> = T extends Value<infer V>
+  ? UnwrapValue8<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue8<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue8<T[K]> } : T
+
+type UnwrapValue8<T> = T extends Value<infer V>
+  ? UnwrapValue9<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue9<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue9<T[K]> } : T
+
+type UnwrapValue9<T> = T extends Value<infer V>
+  ? UnwrapValue10<V>
+  : T extends Array<infer V>
+    ? Array<UnwrapValue10<V>>
+    : T extends BailTypes
+      ? T
+      : T extends object ? { [K in keyof T]: UnwrapValue10<T[K]> } : T
+
+type UnwrapValue10<T> = T extends Value<infer V>
+  ? V // stop recursion
+  : T
index e2db5c1101634721518991b8264c6d9a00144655..8b7cea0bce4d6bc31afb10099e532ccef9344ea5 100644 (file)
@@ -1,5 +1,5 @@
 import { VNode, normalizeVNode, VNodeChild } from './vnode'
-import { ReactiveEffect, UnwrapValues, observable } from '@vue/observer'
+import { ReactiveEffect, UnwrapValue, observable } from '@vue/observer'
 import { isFunction, EMPTY_OBJ } from '@vue/shared'
 import { RenderProxyHandlers } from './componentProxy'
 import { ComponentPropsOptions, PropValidator } from './componentProps'
@@ -14,7 +14,7 @@ type ExtractPropTypes<PropOptions> = {
     : PropOptions[key] extends null | undefined ? any : PropOptions[key]
 }
 
-export interface ComponentPublicProperties<P = Data, S = Data> {
+export type ComponentPublicProperties<P = Data, S = Data> = {
   $state: S
   $props: P
   $attrs: Data
@@ -25,19 +25,20 @@ export interface ComponentPublicProperties<P = Data, S = Data> {
 
   $root: ComponentInstance | null
   $parent: ComponentInstance | null
-}
+} & P &
+  S
 
 export interface ComponentOptions<
   RawProps = ComponentPropsOptions,
   RawBindings = Data | void,
   Props = ExtractPropTypes<RawProps>,
-  Bindings = UnwrapValues<RawBindings>
+  Bindings = UnwrapValue<RawBindings>
 > {
   props?: RawProps
   setup?: (props: Props) => RawBindings
-  render?: <B extends Bindings>(
-    this: ComponentPublicProperties<Props, B>,
-    ctx: ComponentInstance<Props, B>
+  render?: <State extends Bindings>(
+    this: ComponentPublicProperties<Props, State>,
+    ctx: ComponentInstance<Props, State>
   ) => VNodeChild
 }
 
@@ -90,7 +91,7 @@ export function createComponent<
   RawProps,
   RawBindings,
   Props = ExtractPropTypes<RawProps>,
-  Bindings = UnwrapValues<RawBindings>
+  Bindings = UnwrapValue<RawBindings>
 >(
   options: ComponentOptions<RawProps, RawBindings, Props, Bindings>
 ): {