2023-11-10 16:56:29 +08:00
|
|
|
import type { ComputedRef } from './computed'
|
2022-01-30 18:52:23 +08:00
|
|
|
import {
|
|
|
|
activeEffect,
|
2023-02-01 16:20:47 +08:00
|
|
|
getDepFromReactive,
|
2022-01-30 18:52:23 +08:00
|
|
|
shouldTrack,
|
|
|
|
trackEffects,
|
|
|
|
triggerEffects
|
|
|
|
} from './effect'
|
2019-12-04 00:30:24 +08:00
|
|
|
import { TrackOpTypes, TriggerOpTypes } from './operations'
|
2023-04-02 10:17:51 +08:00
|
|
|
import { isArray, hasChanged, IfAny, isFunction, isObject } from '@vue/shared'
|
2022-07-22 11:10:52 +08:00
|
|
|
import {
|
|
|
|
isProxy,
|
|
|
|
toRaw,
|
|
|
|
isReactive,
|
|
|
|
toReactive,
|
|
|
|
isReadonly,
|
|
|
|
isShallow
|
|
|
|
} from './reactive'
|
2021-10-10 06:06:12 +08:00
|
|
|
import type { ShallowReactiveMarker } from './reactive'
|
2019-10-22 23:26:48 +08:00
|
|
|
import { CollectionTypes } from './collectionHandlers'
|
2021-07-08 02:37:28 +08:00
|
|
|
import { createDep, Dep } from './dep'
|
2019-08-16 21:42:46 +08:00
|
|
|
|
2021-09-02 04:49:12 +08:00
|
|
|
declare const RefSymbol: unique symbol
|
2022-05-06 17:07:49 +08:00
|
|
|
export declare const RawSymbol: unique symbol
|
2020-05-04 20:51:01 +08:00
|
|
|
|
2019-10-10 02:01:53 +08:00
|
|
|
export interface Ref<T = any> {
|
2020-10-07 06:16:20 +08:00
|
|
|
value: T
|
2020-05-03 04:16:51 +08:00
|
|
|
/**
|
2020-05-04 20:51:01 +08:00
|
|
|
* 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.
|
2020-05-03 04:16:51 +08:00
|
|
|
*/
|
2020-05-04 20:51:01 +08:00
|
|
|
[RefSymbol]: true
|
2021-06-24 05:22:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type RefBase<T> = {
|
2021-07-08 02:13:23 +08:00
|
|
|
dep?: Dep
|
2021-06-24 05:22:21 +08:00
|
|
|
value: T
|
|
|
|
}
|
|
|
|
|
|
|
|
export function trackRefValue(ref: RefBase<any>) {
|
2022-01-30 18:52:23 +08:00
|
|
|
if (shouldTrack && activeEffect) {
|
2021-06-24 05:22:21 +08:00
|
|
|
ref = toRaw(ref)
|
2021-06-24 05:20:38 +08:00
|
|
|
if (__DEV__) {
|
2022-01-30 18:52:23 +08:00
|
|
|
trackEffects(ref.dep || (ref.dep = createDep()), {
|
2021-06-24 05:20:38 +08:00
|
|
|
target: ref,
|
|
|
|
type: TrackOpTypes.GET,
|
|
|
|
key: 'value'
|
|
|
|
})
|
|
|
|
} else {
|
2022-01-30 18:52:23 +08:00
|
|
|
trackEffects(ref.dep || (ref.dep = createDep()))
|
2021-06-24 05:20:38 +08:00
|
|
|
}
|
2021-06-24 05:22:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function triggerRefValue(ref: RefBase<any>, newVal?: any) {
|
|
|
|
ref = toRaw(ref)
|
2023-02-01 16:20:47 +08:00
|
|
|
const dep = ref.dep
|
|
|
|
if (dep) {
|
2021-06-24 05:20:38 +08:00
|
|
|
if (__DEV__) {
|
2023-02-01 16:20:47 +08:00
|
|
|
triggerEffects(dep, {
|
2021-06-24 05:20:38 +08:00
|
|
|
target: ref,
|
|
|
|
type: TriggerOpTypes.SET,
|
|
|
|
key: 'value',
|
|
|
|
newValue: newVal
|
|
|
|
})
|
|
|
|
} else {
|
2023-02-01 16:20:47 +08:00
|
|
|
triggerEffects(dep)
|
2021-06-24 05:20:38 +08:00
|
|
|
}
|
2021-06-24 05:22:21 +08:00
|
|
|
}
|
2019-08-16 21:42:46 +08:00
|
|
|
}
|
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Checks if a value is a ref object.
|
|
|
|
*
|
|
|
|
* @param r - The value to inspect.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-utilities.html#isref}
|
|
|
|
*/
|
2020-02-22 00:45:42 +08:00
|
|
|
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
|
2019-11-09 02:29:43 +08:00
|
|
|
export function isRef(r: any): r is Ref {
|
2022-01-28 18:35:09 +08:00
|
|
|
return !!(r && r.__v_isRef === true)
|
2019-11-09 02:29:43 +08:00
|
|
|
}
|
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Takes an inner value and returns a reactive and mutable ref object, which
|
|
|
|
* has a single property `.value` that points to the inner value.
|
|
|
|
*
|
|
|
|
* @param value - The object to wrap in the ref.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-core.html#ref}
|
|
|
|
*/
|
2023-04-02 10:17:51 +08:00
|
|
|
export function ref<T extends Ref>(value: T): T
|
2020-04-22 23:54:54 +08:00
|
|
|
export function ref<T>(value: T): Ref<UnwrapRef<T>>
|
2020-03-07 00:32:39 +08:00
|
|
|
export function ref<T = any>(): Ref<T | undefined>
|
2020-01-28 02:13:38 +08:00
|
|
|
export function ref(value?: unknown) {
|
2021-08-24 06:32:58 +08:00
|
|
|
return createRef(value, false)
|
2020-02-22 11:39:32 +08:00
|
|
|
}
|
|
|
|
|
2021-10-10 05:51:09 +08:00
|
|
|
declare const ShallowRefMarker: unique symbol
|
|
|
|
|
2021-12-06 12:18:21 +08:00
|
|
|
export type ShallowRef<T = any> = Ref<T> & { [ShallowRefMarker]?: true }
|
2021-10-10 05:51:09 +08:00
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Shallow version of {@link ref()}.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```js
|
|
|
|
* const state = shallowRef({ count: 1 })
|
|
|
|
*
|
|
|
|
* // does NOT trigger change
|
|
|
|
* state.value.count = 2
|
|
|
|
*
|
|
|
|
* // does trigger change
|
|
|
|
* state.value = { count: 2 }
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param value - The "inner value" for the shallow ref.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowref}
|
|
|
|
*/
|
2023-11-10 13:40:47 +08:00
|
|
|
export function shallowRef<T>(value: MaybeRef<T>): Ref<T> | ShallowRef<T>
|
|
|
|
export function shallowRef<T extends Ref>(value: T): T
|
2021-10-10 05:51:09 +08:00
|
|
|
export function shallowRef<T>(value: T): ShallowRef<T>
|
|
|
|
export function shallowRef<T = any>(): ShallowRef<T | undefined>
|
2020-02-22 11:39:32 +08:00
|
|
|
export function shallowRef(value?: unknown) {
|
|
|
|
return createRef(value, true)
|
|
|
|
}
|
|
|
|
|
2021-09-22 22:11:54 +08:00
|
|
|
function createRef(rawValue: unknown, shallow: boolean) {
|
|
|
|
if (isRef(rawValue)) {
|
|
|
|
return rawValue
|
|
|
|
}
|
|
|
|
return new RefImpl(rawValue, shallow)
|
|
|
|
}
|
|
|
|
|
2020-08-22 01:47:41 +08:00
|
|
|
class RefImpl<T> {
|
|
|
|
private _value: T
|
2021-06-24 05:22:21 +08:00
|
|
|
private _rawValue: T
|
2020-08-22 01:47:41 +08:00
|
|
|
|
2021-07-08 02:13:23 +08:00
|
|
|
public dep?: Dep = undefined
|
2020-08-22 01:47:41 +08:00
|
|
|
public readonly __v_isRef = true
|
|
|
|
|
2023-08-11 17:30:04 +08:00
|
|
|
constructor(
|
|
|
|
value: T,
|
|
|
|
public readonly __v_isShallow: boolean
|
|
|
|
) {
|
2022-01-18 09:17:22 +08:00
|
|
|
this._rawValue = __v_isShallow ? value : toRaw(value)
|
|
|
|
this._value = __v_isShallow ? value : toReactive(value)
|
2020-08-22 01:47:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
get value() {
|
2021-06-24 05:22:21 +08:00
|
|
|
trackRefValue(this)
|
2020-08-22 01:47:41 +08:00
|
|
|
return this._value
|
|
|
|
}
|
|
|
|
|
|
|
|
set value(newVal) {
|
2022-07-22 11:10:52 +08:00
|
|
|
const useDirectValue =
|
|
|
|
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
|
|
|
|
newVal = useDirectValue ? newVal : toRaw(newVal)
|
2021-07-16 04:28:01 +08:00
|
|
|
if (hasChanged(newVal, this._rawValue)) {
|
2020-08-22 01:47:41 +08:00
|
|
|
this._rawValue = newVal
|
2022-07-22 11:10:52 +08:00
|
|
|
this._value = useDirectValue ? newVal : toReactive(newVal)
|
2021-06-24 05:22:21 +08:00
|
|
|
triggerRefValue(this, newVal)
|
2020-08-22 01:47:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Force trigger effects that depends on a shallow ref. This is typically used
|
|
|
|
* after making deep mutations to the inner value of a shallow ref.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```js
|
|
|
|
* const shallow = shallowRef({
|
|
|
|
* greet: 'Hello, world'
|
|
|
|
* })
|
|
|
|
*
|
|
|
|
* // Logs "Hello, world" once for the first run-through
|
|
|
|
* watchEffect(() => {
|
|
|
|
* console.log(shallow.value.greet)
|
|
|
|
* })
|
|
|
|
*
|
|
|
|
* // This won't trigger the effect because the ref is shallow
|
|
|
|
* shallow.value.greet = 'Hello, universe'
|
|
|
|
*
|
|
|
|
* // Logs "Hello, universe"
|
|
|
|
* triggerRef(shallow)
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param ref - The ref whose tied effects shall be executed.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#triggerref}
|
|
|
|
*/
|
2020-04-23 06:00:10 +08:00
|
|
|
export function triggerRef(ref: Ref) {
|
2021-06-24 05:22:21 +08:00
|
|
|
triggerRefValue(ref, __DEV__ ? ref.value : void 0)
|
2020-04-23 06:00:10 +08:00
|
|
|
}
|
|
|
|
|
2023-04-02 10:17:51 +08:00
|
|
|
export type MaybeRef<T = any> = T | Ref<T>
|
|
|
|
export type MaybeRefOrGetter<T = any> = MaybeRef<T> | (() => T)
|
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Returns the inner value if the argument is a ref, otherwise return the
|
|
|
|
* argument itself. This is a sugar function for
|
|
|
|
* `val = isRef(val) ? val.value : val`.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```js
|
|
|
|
* function useFoo(x: number | Ref<number>) {
|
|
|
|
* const unwrapped = unref(x)
|
|
|
|
* // unwrapped is guaranteed to be number now
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param ref - Ref or plain value to be converted into the plain value.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-utilities.html#unref}
|
|
|
|
*/
|
2023-11-10 16:56:29 +08:00
|
|
|
export function unref<T>(ref: MaybeRef<T> | ComputedRef<T>): T {
|
2023-04-06 17:15:27 +08:00
|
|
|
return isRef(ref) ? ref.value : ref
|
2020-02-22 11:39:32 +08:00
|
|
|
}
|
|
|
|
|
2023-04-02 10:17:51 +08:00
|
|
|
/**
|
|
|
|
* Normalizes values / refs / getters to values.
|
|
|
|
* This is similar to {@link unref()}, except that it also normalizes getters.
|
|
|
|
* If the argument is a getter, it will be invoked and its return value will
|
|
|
|
* be returned.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```js
|
|
|
|
* toValue(1) // 1
|
|
|
|
* toValue(ref(1)) // 1
|
|
|
|
* toValue(() => 1) // 1
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param source - A getter, an existing ref, or a non-function value.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-utilities.html#tovalue}
|
|
|
|
*/
|
2023-11-10 16:56:29 +08:00
|
|
|
export function toValue<T>(source: MaybeRefOrGetter<T> | ComputedRef<T>): T {
|
2023-04-02 10:17:51 +08:00
|
|
|
return isFunction(source) ? source() : unref(source)
|
|
|
|
}
|
|
|
|
|
2020-07-29 04:30:56 +08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Returns a reactive proxy for the given object.
|
|
|
|
*
|
|
|
|
* If the object already is reactive, it's returned as-is. If not, a new
|
|
|
|
* reactive proxy is created. Direct child properties that are refs are properly
|
|
|
|
* handled, as well.
|
|
|
|
*
|
|
|
|
* @param objectWithRefs - Either an already-reactive object or a simple object
|
|
|
|
* that contains refs.
|
|
|
|
*/
|
2020-07-29 04:30:56 +08:00
|
|
|
export function proxyRefs<T extends object>(
|
|
|
|
objectWithRefs: T
|
|
|
|
): ShallowUnwrapRef<T> {
|
|
|
|
return isReactive(objectWithRefs)
|
|
|
|
? objectWithRefs
|
|
|
|
: new Proxy(objectWithRefs, shallowUnwrapHandlers)
|
|
|
|
}
|
|
|
|
|
2021-12-11 18:15:44 +08:00
|
|
|
export type CustomRefFactory<T> = (
|
2020-04-15 08:45:41 +08:00
|
|
|
track: () => void,
|
|
|
|
trigger: () => void
|
|
|
|
) => {
|
|
|
|
get: () => T
|
|
|
|
set: (value: T) => void
|
|
|
|
}
|
|
|
|
|
2020-08-22 01:47:41 +08:00
|
|
|
class CustomRefImpl<T> {
|
2021-07-08 02:13:23 +08:00
|
|
|
public dep?: Dep = undefined
|
2021-06-24 05:22:21 +08:00
|
|
|
|
2020-08-22 01:47:41 +08:00
|
|
|
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(
|
2021-06-24 05:22:21 +08:00
|
|
|
() => trackRefValue(this),
|
|
|
|
() => triggerRefValue(this)
|
2020-08-22 01:47:41 +08:00
|
|
|
)
|
|
|
|
this._get = get
|
|
|
|
this._set = set
|
|
|
|
}
|
|
|
|
|
|
|
|
get value() {
|
|
|
|
return this._get()
|
|
|
|
}
|
|
|
|
|
|
|
|
set value(newVal) {
|
|
|
|
this._set(newVal)
|
2020-04-15 08:45:41 +08:00
|
|
|
}
|
2020-08-22 01:47:41 +08:00
|
|
|
}
|
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
|
|
|
* Creates a customized ref with explicit control over its dependency tracking
|
|
|
|
* and updates triggering.
|
|
|
|
*
|
|
|
|
* @param factory - The function that receives the `track` and `trigger` callbacks.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#customref}
|
|
|
|
*/
|
2020-08-22 01:47:41 +08:00
|
|
|
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
|
|
|
|
return new CustomRefImpl(factory) as any
|
2020-04-15 08:45:41 +08:00
|
|
|
}
|
|
|
|
|
2021-09-02 04:49:12 +08:00
|
|
|
export type ToRefs<T = any> = {
|
2021-11-25 17:39:09 +08:00
|
|
|
[K in keyof T]: ToRef<T[K]>
|
2021-09-02 04:49:12 +08:00
|
|
|
}
|
2023-03-31 17:06:10 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts a reactive object to a plain object where each property of the
|
|
|
|
* resulting object is a ref pointing to the corresponding property of the
|
|
|
|
* original object. Each individual ref is created using {@link toRef()}.
|
|
|
|
*
|
|
|
|
* @param object - Reactive object to be made into an object of linked refs.
|
|
|
|
* @see {@link https://vuejs.org/api/reactivity-utilities.html#torefs}
|
|
|
|
*/
|
2020-04-25 01:10:16 +08:00
|
|
|
export function toRefs<T extends object>(object: T): ToRefs<T> {
|
2020-04-16 04:45:20 +08:00
|
|
|
if (__DEV__ && !isProxy(object)) {
|
2019-11-05 23:44:28 +08:00
|
|
|
console.warn(`toRefs() expects a reactive object but received a plain one.`)
|
|
|
|
}
|
2020-08-19 00:11:13 +08:00
|
|
|
const ret: any = isArray(object) ? new Array(object.length) : {}
|
2019-08-20 21:38:00 +08:00
|
|
|
for (const key in object) {
|
2023-04-02 10:17:51 +08:00
|
|
|
ret[key] = propertyToRef(object, key)
|
2019-08-20 21:38:00 +08:00
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2020-08-22 01:47:41 +08:00
|
|
|
class ObjectRefImpl<T extends object, K extends keyof T> {
|
|
|
|
public readonly __v_isRef = true
|
|
|
|
|
2021-12-11 16:41:58 +08:00
|
|
|
constructor(
|
|
|
|
private readonly _object: T,
|
|
|
|
private readonly _key: K,
|
|
|
|
private readonly _defaultValue?: T[K]
|
|
|
|
) {}
|
2020-08-22 01:47:41 +08:00
|
|
|
|
|
|
|
get value() {
|
2021-12-11 16:41:58 +08:00
|
|
|
const val = this._object[this._key]
|
2023-07-10 18:18:53 +08:00
|
|
|
return val === undefined ? this._defaultValue! : val
|
2020-08-22 01:47:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
set value(newVal) {
|
|
|
|
this._object[this._key] = newVal
|
|
|
|
}
|
2023-02-01 16:20:47 +08:00
|
|
|
|
|
|
|
get dep(): Dep | undefined {
|
|
|
|
return getDepFromReactive(toRaw(this._object), this._key)
|
|
|
|
}
|
2020-08-22 01:47:41 +08:00
|
|
|
}
|
|
|
|
|
2023-04-02 10:17:51 +08:00
|
|
|
class GetterRefImpl<T> {
|
|
|
|
public readonly __v_isRef = true
|
|
|
|
public readonly __v_isReadonly = true
|
|
|
|
constructor(private readonly _getter: () => T) {}
|
|
|
|
get value() {
|
|
|
|
return this._getter()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-16 15:46:49 +08:00
|
|
|
export type ToRef<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>
|
2021-10-10 05:51:09 +08:00
|
|
|
|
2023-03-31 17:06:10 +08:00
|
|
|
/**
|
2023-04-02 10:17:51 +08:00
|
|
|
* Used to normalize values / refs / getters into refs.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```js
|
|
|
|
* // returns existing refs as-is
|
|
|
|
* toRef(existingRef)
|
|
|
|
*
|
|
|
|
* // creates a ref that calls the getter on .value access
|
|
|
|
* toRef(() => props.foo)
|
|
|
|
*
|
|
|
|
* // creates normal refs from non-function values
|
|
|
|
* // equivalent to ref(1)
|
|
|
|
* toRef(1)
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Can also be used to create a ref for a property on a source reactive object.
|
|
|
|
* The created ref is synced with its source property: mutating the source
|
|
|
|
* property will update the ref, and vice-versa.
|
2023-03-31 17:06:10 +08:00
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```js
|
|
|
|
* const state = reactive({
|
|
|
|
* foo: 1,
|
|
|
|
* bar: 2
|
|
|
|
* })
|
|
|
|
*
|
|
|
|
* const fooRef = toRef(state, 'foo')
|
|
|
|
*
|
|
|
|
* // mutating the ref updates the original
|
|
|
|
* fooRef.value++
|
|
|
|
* console.log(state.foo) // 2
|
|
|
|
*
|
|
|
|
* // mutating the original also updates the ref
|
|
|
|
* state.foo++
|
|
|
|
* console.log(fooRef.value) // 3
|
|
|
|
* ```
|
|
|
|
*
|
2023-04-02 10:17:51 +08:00
|
|
|
* @param source - A getter, an existing ref, a non-function value, or a
|
|
|
|
* reactive object to create a property ref from.
|
|
|
|
* @param [key] - (optional) Name of the property in the reactive object.
|
2023-03-31 17:06:10 +08:00
|
|
|
* @see {@link https://vuejs.org/api/reactivity-utilities.html#toref}
|
|
|
|
*/
|
2023-04-02 10:17:51 +08:00
|
|
|
export function toRef<T>(
|
|
|
|
value: T
|
|
|
|
): T extends () => infer R
|
|
|
|
? Readonly<Ref<R>>
|
|
|
|
: T extends Ref
|
|
|
|
? T
|
|
|
|
: Ref<UnwrapRef<T>>
|
2020-04-15 08:49:18 +08:00
|
|
|
export function toRef<T extends object, K extends keyof T>(
|
2019-08-20 21:38:00 +08:00
|
|
|
object: T,
|
|
|
|
key: K
|
2021-12-11 16:41:58 +08:00
|
|
|
): 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>>
|
2023-04-02 10:17:51 +08:00
|
|
|
export function toRef(
|
|
|
|
source: Record<string, any> | MaybeRef,
|
|
|
|
key?: string,
|
|
|
|
defaultValue?: unknown
|
|
|
|
): Ref {
|
|
|
|
if (isRef(source)) {
|
|
|
|
return source
|
|
|
|
} else if (isFunction(source)) {
|
2023-04-10 14:06:56 +08:00
|
|
|
return new GetterRefImpl(source) as any
|
2023-04-02 10:17:51 +08:00
|
|
|
} else if (isObject(source) && arguments.length > 1) {
|
|
|
|
return propertyToRef(source, key!, defaultValue)
|
|
|
|
} else {
|
|
|
|
return ref(source)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-19 07:49:28 +08:00
|
|
|
function propertyToRef(
|
|
|
|
source: Record<string, any>,
|
|
|
|
key: string,
|
|
|
|
defaultValue?: unknown
|
|
|
|
) {
|
|
|
|
const val = source[key]
|
2021-12-11 16:41:58 +08:00
|
|
|
return isRef(val)
|
|
|
|
? val
|
2023-05-19 07:49:28 +08:00
|
|
|
: (new ObjectRefImpl(source, key, defaultValue) as any)
|
2019-08-16 21:42:46 +08:00
|
|
|
}
|
|
|
|
|
2020-01-17 06:47:47 +08:00
|
|
|
// corner case when use narrows type
|
|
|
|
// Ex. type RelativePath = string & { __brand: unknown }
|
|
|
|
// RelativePath extends object -> true
|
2020-05-02 04:14:30 +08:00
|
|
|
type 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
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
export interface RefUnwrapBailTypes {}
|
2020-01-17 06:47:47 +08:00
|
|
|
|
2020-07-29 04:30:56 +08:00
|
|
|
export type ShallowUnwrapRef<T> = {
|
2021-07-16 03:58:20 +08:00
|
|
|
[K in keyof T]: T[K] extends Ref<infer V>
|
2022-10-26 16:27:42 +08:00
|
|
|
? V // if `V` is `unknown` that means it does not extend `Ref` and is undefined
|
|
|
|
: T[K] extends Ref<infer V> | undefined
|
2022-10-28 09:39:34 +08:00
|
|
|
? unknown extends V
|
|
|
|
? undefined
|
|
|
|
: V | undefined
|
|
|
|
: T[K]
|
2020-07-29 04:30:56 +08:00
|
|
|
}
|
|
|
|
|
2021-10-10 05:51:09 +08:00
|
|
|
export type UnwrapRef<T> = T extends ShallowRef<infer V>
|
|
|
|
? V
|
|
|
|
: T extends Ref<infer V>
|
2020-04-09 04:33:06 +08:00
|
|
|
? UnwrapRefSimple<V>
|
2020-06-18 04:06:55 +08:00
|
|
|
: UnwrapRefSimple<T>
|
2020-04-09 04:33:06 +08:00
|
|
|
|
2021-07-28 23:15:08 +08:00
|
|
|
export type UnwrapRefSimple<T> = T extends
|
2020-05-02 04:14:30 +08:00
|
|
|
| Function
|
|
|
|
| CollectionTypes
|
|
|
|
| BaseTypes
|
|
|
|
| Ref
|
|
|
|
| RefUnwrapBailTypes[keyof RefUnwrapBailTypes]
|
2022-05-06 17:07:49 +08:00
|
|
|
| { [RawSymbol]?: true }
|
2020-04-09 04:33:06 +08:00
|
|
|
? T
|
2022-10-26 16:27:42 +08:00
|
|
|
: T extends ReadonlyArray<any>
|
2021-11-26 10:54:12 +08:00
|
|
|
? { [K in keyof T]: UnwrapRefSimple<T[K]> }
|
2021-10-10 05:51:09 +08:00
|
|
|
: T extends object & { [ShallowReactiveMarker]?: never }
|
2021-07-28 23:12:46 +08:00
|
|
|
? {
|
|
|
|
[P in keyof T]: P extends symbol ? T[P] : UnwrapRef<T[P]>
|
|
|
|
}
|
2021-07-20 06:24:18 +08:00
|
|
|
: T
|