import { track, trigger } from './effect' import { TrackOpTypes, TriggerOpTypes } from './operations' import { isObject } from '@vue/shared' import { reactive, isReactive } from './reactive' import { ComputedRef } from './computed' import { CollectionTypes } from './collectionHandlers' const isRefSymbol = Symbol() export interface Ref { // This field is necessary to allow TS to differentiate a Ref from a plain // object that happens to have a "value" field. // However, checking a symbol on an arbitrary object is much slower than // checking a plain property, so we use a _isRef plain property for isRef() // check in the actual implementation. // The reason for not just declaring _isRef in the interface is because we // don't want this internal field to leak into userland autocompletion - // a private symbol, on the other hand, achieves just that. [isRefSymbol]: true value: UnwrapRef } const convert = (val: T): T => isObject(val) ? reactive(val) : val export function isRef(r: any): r is Ref { return r ? r._isRef === true : false } 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, TrackOpTypes.GET, 'value') return raw }, set value(newVal) { raw = convert(newVal) trigger( r, TriggerOpTypes.SET, 'value', __DEV__ ? { newValue: newVal } : void 0 ) } } return r } export function toRefs( object: T ): { [K in keyof T]: Ref } { if (__DEV__ && !isReactive(object)) { console.warn(`toRefs() expects a reactive object but received a plain one.`) } 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 } } as any } type UnwrapArray = { [P in keyof T]: UnwrapRef } // 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> & UnwrapArray : 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']