import { track, trigger } from './effect' import { OperationTypes } from './operations' import { isObject } from '@vue/shared' import { reactive } from './reactive' import { ComputedRef } from './computed' export interface Ref { _isRef: true value: UnwrapRef } const convert = (val: any): any => (isObject(val) ? reactive(val) : val) export function ref(raw: T): T export function ref(raw: T): Ref export function ref(raw: any) { if (isRef(raw)) { return raw } raw = convert(raw) const v = { _isRef: true, get value() { track(v, OperationTypes.GET, '') return raw }, set value(newVal) { raw = convert(newVal) trigger(v, OperationTypes.SET, '') } } return v as Ref } export function isRef(v: any): v is Ref { return v ? v._isRef === true : false } export function toRefs( object: T ): { [K in keyof T]: Ref } { const ret: any = {} for (const key in object) { ret[key] = toProxyRef(object, key) } return ret } function toProxyRef( object: T, key: K ): Ref { return { _isRef: true, get value(): any { return object[key] }, set value(newVal) { object[key] = newVal } } } type BailTypes = | Function | Map | Set | WeakMap | WeakSet // Recursively unwraps nested value bindings. export type UnwrapRef = { cRef: T extends ComputedRef ? UnwrapRef : T ref: T extends Ref ? UnwrapRef : T array: T extends Array ? Array> : T object: { [K in keyof T]: UnwrapRef } }[T extends ComputedRef ? 'cRef' : T extends Ref ? 'ref' : T extends Array ? 'array' : T extends BailTypes ? 'ref' // bail out on types that shouldn't be unwrapped : T extends object ? 'object' : 'ref']