import { defineReactive } from 'core/observer/index' import { isReactive, type ShallowReactiveMarker } from './reactive' import type { IfAny } from 'typescript/utils' import Dep from 'core/observer/dep' import { warn, isArray } from 'core/util' declare const RefSymbol: unique symbol export declare const RawSymbol: unique symbol export interface Ref { value: T /** * Type differentiator only. * We need this to be in public d.ts but don't want it to show up in IDE * autocomplete, so we use a private Symbol instead. */ [RefSymbol]: true /** * @private */ dep?: Dep } export function isRef(r: Ref | unknown): r is Ref export function isRef(r: any): r is Ref { return !!(r && r.__v_isRef === true) } export function ref( value: T ): [T] extends [Ref] ? T : Ref> export function ref(value: T): Ref> export function ref(): Ref export function ref(value?: unknown) { return createRef(value, false) } declare const ShallowRefMarker: unique symbol export type ShallowRef = Ref & { [ShallowRefMarker]?: true } export function shallowRef( value: T ): T extends Ref ? T : ShallowRef export function shallowRef(value: T): ShallowRef export function shallowRef(): ShallowRef export function shallowRef(value?: unknown) { return createRef(value, true) } function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } const ref: any = { __v_isRef: true, __v_isShallow: shallow } ref.dep = defineReactive(ref, 'value', rawValue, null, shallow) return ref } export function triggerRef(ref: Ref) { if (__DEV__ && !ref.dep) { warn(`received object is not a triggerable ref.`) } ref.dep && ref.dep.notify() } export function unref(ref: T | Ref): T { return isRef(ref) ? (ref.value as any) : ref } export type CustomRefFactory = ( track: () => void, trigger: () => void ) => { get: () => T set: (value: T) => void } class CustomRefImpl { public dep = new Dep() private readonly _get: ReturnType>['get'] private readonly _set: ReturnType>['set'] public readonly __v_isRef = true constructor(factory: CustomRefFactory) { const { get, set } = factory( () => this.dep.depend(), () => this.dep.notify() ) this._get = get this._set = set } get value() { return this._get() } set value(newVal) { this._set(newVal) } } export function customRef(factory: CustomRefFactory): Ref { return new CustomRefImpl(factory) as any } export type ToRefs = { [K in keyof T]: ToRef } export function toRefs(object: T): ToRefs { if (__DEV__ && !isReactive(object)) { warn(`toRefs() expects a reactive object but received a plain one.`) } const ret: any = isArray(object) ? new Array(object.length) : {} for (const key in object) { ret[key] = toRef(object, key) } return ret } class ObjectRefImpl { public readonly __v_isRef = true constructor( private readonly _object: T, private readonly _key: K, private readonly _defaultValue?: T[K] ) {} get value() { const val = this._object[this._key] return val === undefined ? (this._defaultValue as T[K]) : val } set value(newVal) { this._object[this._key] = newVal } } export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> export function toRef( object: T, key: K ): ToRef export function toRef( object: T, key: K, defaultValue: T[K] ): ToRef> export function toRef( object: T, key: K, defaultValue?: T[K] ): ToRef { const val = object[key] return isRef(val) ? val : (new ObjectRefImpl(object, key, defaultValue) as any) } /** * This is a special exported interface for other packages to declare * additional types that should bail out for ref unwrapping. For example * \@vue/runtime-dom can declare it like so in its d.ts: * * ``` ts * declare module 'vue' { * export interface RefUnwrapBailTypes { * runtimeDOMBailTypes: Node | Window * } * } * ``` * * Note that api-extractor somehow refuses to include `declare module` * augmentations in its generated d.ts, so we have to manually append them * to the final generated d.ts in our build process. */ export interface RefUnwrapBailTypes {} export type ShallowUnwrapRef = { [K in keyof T]: T[K] extends Ref ? V : // if `V` is `unknown` that means it does not extend `Ref` and is undefined T[K] extends Ref | undefined ? unknown extends V ? undefined : V | undefined : T[K] } export type UnwrapRef = T extends ShallowRef ? V : T extends Ref ? UnwrapRefSimple : UnwrapRefSimple type BaseTypes = string | number | boolean type CollectionTypes = IterableCollections | WeakCollections type IterableCollections = Map | Set type WeakCollections = WeakMap | WeakSet export type UnwrapRefSimple = T extends | Function | CollectionTypes | BaseTypes | Ref | RefUnwrapBailTypes[keyof RefUnwrapBailTypes] | { [RawSymbol]?: true } ? T : T extends Array ? { [K in keyof T]: UnwrapRefSimple } : T extends object & { [ShallowReactiveMarker]?: never } ? { [P in keyof T]: P extends symbol ? T[P] : UnwrapRef } : T