Skip to main content
Module

x/vue3_reactivity/src/ref.ts

vue3_reactivity is forck by @vue/reactivity for deno.
Latest
File
// deno-lint-ignore-file no-explicit-any ban-types no-empty-interfaceimport { activeEffect, shouldTrack, trackEffects, triggerEffects} from './effect.ts'import { TrackOpTypes, TriggerOpTypes } from './operations.ts'import { isArray, hasChanged, IfAny } from '../shared/index.ts'import { isProxy, toRaw, isReactive, toReactive } from './reactive.ts'import type { ShallowReactiveMarker } from './reactive.ts'import { CollectionTypes } from './collectionHandlers.ts'import { createDep, Dep } from './dep.ts'import { __DEV__ } from "../dev.ts";
declare const RefSymbol: unique symbolexport declare const RawSymbol: unique symbol
export interface Ref<T = any> { 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}
type RefBase<T> = { dep?: Dep value: T}
export function trackRefValue(ref: RefBase<any>) { if (shouldTrack && activeEffect) { ref = toRaw(ref) if (__DEV__) { trackEffects(ref.dep || (ref.dep = createDep()), { target: ref, type: TrackOpTypes.GET, key: 'value' }) } else { trackEffects(ref.dep || (ref.dep = createDep())) } }}
export function triggerRefValue(ref: RefBase<any>, newVal?: any) { ref = toRaw(ref) if (ref.dep) { if (__DEV__) { triggerEffects(ref.dep, { target: ref, type: TriggerOpTypes.SET, key: 'value', newValue: newVal }) } else { triggerEffects(ref.dep) } }}
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>export function isRef(r: any): r is Ref { return !!(r && r.__v_isRef === true)}
export function ref<T extends object>( value: T): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>export function ref<T>(value: T): Ref<UnwrapRef<T>>export function ref<T = any>(): Ref<T | undefined>export function ref(value?: unknown) { return createRef(value, false)}
declare const ShallowRefMarker: unique symbol
export type ShallowRef<T = any> = Ref<T> & { [ShallowRefMarker]?: true }
export function shallowRef<T extends object>( value: T): T extends Ref ? T : ShallowRef<T>export function shallowRef<T>(value: T): ShallowRef<T>export function shallowRef<T = any>(): ShallowRef<T | undefined>export function shallowRef(value?: unknown) { return createRef(value, true)}
function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } return new RefImpl(rawValue, shallow)}
class RefImpl<T> { private _value: T private _rawValue: T
public dep?: Dep = undefined public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) { this._rawValue = __v_isShallow ? value : toRaw(value) this._value = __v_isShallow ? value : toReactive(value) }
get value() { trackRefValue(this) return this._value }
set value(newVal) { newVal = this.__v_isShallow ? newVal : toRaw(newVal) if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal this._value = this.__v_isShallow ? newVal : toReactive(newVal) triggerRefValue(this, newVal) } }}
export function triggerRef(ref: Ref) { triggerRefValue(ref, __DEV__ ? ref.value : void 0)}
export function unref<T>(ref: T | Ref<T>): T { return isRef(ref) ? (ref.value as any) : ref}
const shallowUnwrapHandlers: ProxyHandler<any> = { get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), set: (target, key, value, receiver) => { const oldValue = target[key] if (isRef(oldValue) && !isRef(value)) { oldValue.value = value return true } else { return Reflect.set(target, key, value, receiver) } }}
export function proxyRefs<T extends object>( objectWithRefs: T): ShallowUnwrapRef<T> { return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers)}
export type CustomRefFactory<T> = ( track: () => void, trigger: () => void) => { get: () => T set: (value: T) => void}
class CustomRefImpl<T> { public dep?: Dep = undefined
private readonly _get: ReturnType<CustomRefFactory<T>>['get'] private readonly _set: ReturnType<CustomRefFactory<T>>['set']
public readonly __v_isRef = true
constructor(factory: CustomRefFactory<T>) { const { get, set } = factory( () => trackRefValue(this), () => triggerRefValue(this) ) this._get = get this._set = set }
get value() { return this._get() }
set value(newVal) { this._set(newVal) }}
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> { return new CustomRefImpl(factory) as any}
export type ToRefs<T = any> = { [K in keyof T]: ToRef<T[K]>}export function toRefs<T extends object>(object: T): ToRefs<T> { if (__DEV__ && !isProxy(object)) { console.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<T extends object, K extends keyof T> { 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<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>
export function toRef<T extends object, K extends keyof T>( object: T, key: K): ToRef<T[K]>
export function toRef<T extends object, K extends keyof T>( object: T, key: K, defaultValue: T[K]): ToRef<Exclude<T[K], undefined>>
export function toRef<T extends object, K extends keyof T>( object: T, key: K, defaultValue?: T[K]): ToRef<T[K]> { const val = object[key] return isRef(val) ? val : (new ObjectRefImpl(object, key, defaultValue) as any)}
// corner case when use narrows type// Ex. type RelativePath = string & { __brand: unknown }// RelativePath extends object -> truetype BaseTypes = string | number | boolean
/** * 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/reactivity' { * 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<T> = { [K in keyof T]: T[K] extends Ref<infer V> ? V : // if `V` is `unknown` that means it does not extend `Ref` and is undefined T[K] extends Ref<infer V> | undefined ? unknown extends V ? undefined : V | undefined : T[K]}
export type UnwrapRef<T> = T extends ShallowRef<infer V> ? V : T extends Ref<infer V> ? UnwrapRefSimple<V> : UnwrapRefSimple<T>
export type UnwrapRefSimple<T> = T extends | Function | CollectionTypes | BaseTypes | Ref | RefUnwrapBailTypes[keyof RefUnwrapBailTypes] | { [RawSymbol]?: true } ? T : T extends Array<any> ? { [K in keyof T]: UnwrapRefSimple<T[K]> } : T extends object & { [ShallowReactiveMarker]?: never } ? { [P in keyof T]: P extends symbol ? T[P] : UnwrapRef<T[P]> } : T