import { track, trigger } from './effect' import { OperationTypes } from './operations' import { isObject } from '@vue/shared' import { reactive } from './reactive' export const knownRefs = new WeakSet() export const isRefSymbol = Symbol() export interface Ref { // this is a type-only field to avoid objects with 'value' property being // treated as a ref by TypeScript [isRefSymbol]: true value: UnwrapNestedRefs } export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRef const convert = (val: any): any => (isObject(val) ? reactive(val) : val) export function ref(raw: T): Ref { raw = convert(raw) const v = { get value() { track(v, OperationTypes.GET, '') return raw }, set value(newVal) { raw = convert(newVal) trigger(v, OperationTypes.SET, '') } } knownRefs.add(v) return v as Ref } export function isRef(v: any): v is Ref { return knownRefs.has(v) } 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 { const v = { get value() { return object[key] }, set value(newVal) { object[key] = newVal } } knownRefs.add(v) return v as Ref } type BailTypes = | Function | Map | Set | WeakMap | WeakSet // Recursively unwraps nested value bindings. // Unfortunately TS cannot do recursive types, but this should be enough for // practical use cases... export type UnwrapRef = T extends Ref ? UnwrapRef2 : T extends Array ? Array> : T extends BailTypes ? T // bail out on types that shouldn't be unwrapped : T extends object ? { [K in keyof T]: UnwrapRef2 } : T type UnwrapRef2 = T extends Ref ? UnwrapRef3 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef3 } : T type UnwrapRef3 = T extends Ref ? UnwrapRef4 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef4 } : T type UnwrapRef4 = T extends Ref ? UnwrapRef5 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef5 } : T type UnwrapRef5 = T extends Ref ? UnwrapRef6 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef6 } : T type UnwrapRef6 = T extends Ref ? UnwrapRef7 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef7 } : T type UnwrapRef7 = T extends Ref ? UnwrapRef8 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef8 } : T type UnwrapRef8 = T extends Ref ? UnwrapRef9 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef9 } : T type UnwrapRef9 = T extends Ref ? UnwrapRef10 : T extends Array ? Array> : T extends BailTypes ? T : T extends object ? { [K in keyof T]: UnwrapRef10 } : T type UnwrapRef10 = T extends Ref ? V // stop recursion : T