| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- import {
- activeEffect,
- shouldTrack,
- trackEffects,
- triggerEffects
- } from './effect'
- import { TrackOpTypes, TriggerOpTypes } from './operations'
- import { isArray, hasChanged, IfAny } from '@vue/shared'
- import { isProxy, toRaw, isReactive, toReactive } from './reactive'
- import type { ShallowReactiveMarker } from './reactive'
- import { CollectionTypes } from './collectionHandlers'
- import { createDep, Dep } from './dep'
- declare const RefSymbol: unique symbol
- export 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 -> true
- 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
- * }
- * }
- * ```
- *
- * 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
|