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