2019-08-16 21:42:46 +08:00
|
|
|
import { track, trigger } from './effect'
|
|
|
|
import { OperationTypes } from './operations'
|
|
|
|
import { isObject } from '@vue/shared'
|
|
|
|
import { reactive } from './reactive'
|
|
|
|
|
2019-10-06 23:46:09 +08:00
|
|
|
export const refSymbol = Symbol(__DEV__ ? 'refSymbol' : undefined)
|
2019-10-06 03:46:36 +08:00
|
|
|
|
2019-08-16 21:42:46 +08:00
|
|
|
export interface Ref<T> {
|
2019-10-06 23:46:09 +08:00
|
|
|
[refSymbol]: true
|
2019-08-16 22:52:45 +08:00
|
|
|
value: UnwrapNestedRefs<T>
|
2019-08-16 21:42:46 +08:00
|
|
|
}
|
|
|
|
|
2019-08-19 10:48:46 +08:00
|
|
|
export type UnwrapNestedRefs<T> = T extends Ref<any> ? T : UnwrapRef<T>
|
2019-08-16 22:52:45 +08:00
|
|
|
|
2019-08-16 21:42:46 +08:00
|
|
|
const convert = (val: any): any => (isObject(val) ? reactive(val) : val)
|
|
|
|
|
|
|
|
export function ref<T>(raw: T): Ref<T> {
|
|
|
|
raw = convert(raw)
|
|
|
|
const v = {
|
2019-10-06 23:46:09 +08:00
|
|
|
[refSymbol]: true,
|
2019-08-16 21:42:46 +08:00
|
|
|
get value() {
|
|
|
|
track(v, OperationTypes.GET, '')
|
|
|
|
return raw
|
|
|
|
},
|
|
|
|
set value(newVal) {
|
|
|
|
raw = convert(newVal)
|
|
|
|
trigger(v, OperationTypes.SET, '')
|
|
|
|
}
|
|
|
|
}
|
2019-08-20 21:38:00 +08:00
|
|
|
return v as Ref<T>
|
2019-08-16 21:42:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function isRef(v: any): v is Ref<any> {
|
2019-10-06 23:46:09 +08:00
|
|
|
return v ? v[refSymbol] === true : false
|
2019-08-20 21:38:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function toRefs<T extends object>(
|
|
|
|
object: T
|
|
|
|
): { [K in keyof T]: Ref<T[K]> } {
|
|
|
|
const ret: any = {}
|
|
|
|
for (const key in object) {
|
|
|
|
ret[key] = toProxyRef(object, key)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
function toProxyRef<T extends object, K extends keyof T>(
|
|
|
|
object: T,
|
|
|
|
key: K
|
|
|
|
): Ref<T[K]> {
|
|
|
|
const v = {
|
2019-10-06 23:46:09 +08:00
|
|
|
[refSymbol]: true,
|
2019-08-20 21:38:00 +08:00
|
|
|
get value() {
|
|
|
|
return object[key]
|
|
|
|
},
|
|
|
|
set value(newVal) {
|
|
|
|
object[key] = newVal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return v as Ref<T[K]>
|
2019-08-16 21:42:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type BailTypes =
|
|
|
|
| Function
|
|
|
|
| Map<any, any>
|
|
|
|
| Set<any>
|
|
|
|
| WeakMap<any, any>
|
|
|
|
| WeakSet<any>
|
|
|
|
|
|
|
|
// Recursively unwraps nested value bindings.
|
2019-10-07 08:11:52 +08:00
|
|
|
export type UnwrapRef<T> = {
|
|
|
|
ref: T extends Ref<infer V> ? UnwrapRef<V> : T
|
|
|
|
array: T extends Array<infer V> ? Array<UnwrapRef<V>> : T
|
|
|
|
object: { [K in keyof T]: UnwrapRef<T[K]> }
|
|
|
|
stop: T
|
|
|
|
}[T extends Ref<any>
|
|
|
|
? 'ref'
|
|
|
|
: T extends Array<any>
|
|
|
|
? 'array'
|
2019-08-16 21:42:46 +08:00
|
|
|
: T extends BailTypes
|
2019-10-07 08:11:52 +08:00
|
|
|
? 'stop' // bail out on types that shouldn't be unwrapped
|
|
|
|
: T extends object ? 'object' : 'stop']
|