import { track, trigger } from './effect' import { OperationTypes } from './operations' import { isObject } from '@vue/shared' import { reactive } from './reactive' import { ComputedRef } from './computed' import { CollectionTypes } from './collectionHandlers' export interface Ref { _isRef: true value: UnwrapRef } const convert = (val: T): T => isObject(val) ? reactive(val) : val export function ref(raw: T): T export function ref(raw: T): Ref export function ref(): Ref export function ref(raw?: unknown) { if (isRef(raw)) { return raw } raw = convert(raw) const r = { _isRef: true, get value() { track(r, OperationTypes.GET, '') return raw }, set value(newVal) { raw = convert(newVal) trigger(r, OperationTypes.SET, '') } } return r as Ref } export function isRef(r: any): r is Ref { return r ? r._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 } } } // 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 Function | CollectionTypes ? 'ref' // bail out on types that shouldn't be unwrapped : T extends object ? 'object' : 'ref']