Vue 3 Ref 源码解析

本文档将逐行解析 Vue 3 中 ref.ts 文件的源码实现,深入理解 Vue 3 的响应式系统中 ref 的工作原理。

文件头部导入部分

typescript 复制代码
import {
  type IfAny,
  hasChanged,
  isArray,
  isFunction,
  isObject,
} from '@vue/shared'
import { Dep, getDepFromReactive } from './dep'
import {
  type Builtin,
  type ShallowReactiveMarker,
  isProxy,
  isReactive,
  isReadonly,
  isShallow,
  toRaw,
  toReactive,
} from './reactive'
import type { ComputedRef, WritableComputedRef } from './computed'
import { ReactiveFlags, TrackOpTypes, TriggerOpTypes } from './constants'
import { warn } from './warning'

导入部分引入了多个工具函数和类型定义:

  • @vue/shared 导入通用工具函数和类型
  • dep.ts 导入依赖追踪相关类
  • reactive.ts 导入响应式系统核心函数
  • computed.ts 导入计算属性相关类型
  • constants.ts 导入常量枚举
  • warning.ts 导入警告函数
typescript 复制代码
declare const RefSymbol: unique symbol
export declare const RawSymbol: unique symbol

声明了两个唯一的 symbol 类型,用于类型系统中的标识符。RefSymbol 用于区分 Ref 对象,而 RawSymbol 在这里重新声明,可能用于标识原始值。

Ref 接口定义

typescript 复制代码
export interface Ref<T = any, S = T> {
  get value(): T
  set value(_: S)
  /**
   * 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
}

定义了 Ref 接口,它具有以下特征:

  1. 有一个 value 属性,具有 getter 和 setter
  2. 使用 RefSymbol 作为类型区分标识符,这样可以在运行时检查一个对象是否为 Ref

isRef 函数

typescript 复制代码
/**
 * Checks if a value is a ref object.
 *
 * @param r - The value to inspect.
 * @see {@link https://vuejs.org/api/reactivity-utilities.html#isref}
 */
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
  return r ? r[ReactiveFlags.IS_REF] === true : false
}

isRef 函数用于检查一个值是否为 Ref 对象。通过检查对象的 ReactiveFlags.IS_REF 属性是否为 true 来判断。

ref 函数

typescript 复制代码
/**
 * 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}
 */
export function ref<T>(
  value: T,
): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {
  return createRef(value, false)
}

ref 函数创建一个响应式的 ref 对象。函数重载支持两种情况:

  1. 传入一个值,创建对应的 ref
  2. 不传值,创建一个值为 undefined 的 ref

实际实现委托给 createRef 函数,第二个参数 false 表示创建的是深度响应式 ref。

ShallowRef 相关类型和函数

typescript 复制代码
declare const ShallowRefMarker: unique symbol

export type ShallowRef<T = any, S = T> = Ref<T, S> & {
  [ShallowRefMarker]?: true
}

声明了 ShallowRefMarker symbol 并定义了 ShallowRef 类型,它是 Ref 的扩展,添加了 ShallowRefMarker 标记。

typescript 复制代码
/**
 * 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}
 */
export function shallowRef<T>(
  value: T,
): Ref extends T
  ? T extends Ref
    ? IfAny<T, ShallowRef<T>, T>
    : ShallowRef<T>
  : ShallowRef<T>
export function shallowRef<T = any>(): ShallowRef<T | undefined>
export function shallowRef(value?: unknown) {
  return createRef(value, true)
}

shallowRef 函数创建一个浅层响应式的 ref 对象。与 ref 不同,它只对 .value 的赋值操作是响应式的,而对值内部属性的修改不是响应式的。

createRef 函数

typescript 复制代码
function createRef(rawValue: unknown, shallow: boolean) {
  if (isRef(rawValue)) {
    return rawValue
  }
  return new RefImpl(rawValue, shallow)
}

createRef 是创建 ref 的内部函数:

  1. 如果传入的值已经是 ref,则直接返回
  2. 否则创建一个新的 RefImpl 实例

RefImpl 类

typescript 复制代码
/**
 * @internal
 */
class RefImpl<T = any> {
  _value: T
  private _rawValue: T

  dep: Dep = new Dep()

  public readonly [ReactiveFlags.IS_REF] = true
  public readonly [ReactiveFlags.IS_SHALLOW]: boolean = false

  constructor(value: T, isShallow: boolean) {
    this._rawValue = isShallow ? value : toRaw(value)
    this._value = isShallow ? value : toReactive(value)
    this[ReactiveFlags.IS_SHALLOW] = isShallow
  }

RefImpl 是 Ref 的具体实现类:

构造函数中根据是否为浅层响应式来决定如何处理传入的值。

typescript 复制代码
  get value() {
    if (__DEV__) {
      this.dep.track({
        target: this,
        type: TrackOpTypes.GET,
        key: 'value',
      })
    } else {
      this.dep.track()
    }
    return this._value
  }

value 的 getter 方法:

  • 在开发环境下,会跟踪详细的调试信息
  • 在生产环境下,简化依赖追踪
  • 返回 _value
typescript 复制代码
  set value(newValue) {
    const oldValue = this._rawValue
    const useDirectValue =
      this[ReactiveFlags.IS_SHALLOW] ||
      isShallow(newValue) ||
      isReadonly(newValue)
    newValue = useDirectValue ? newValue : toRaw(newValue)
    if (hasChanged(newValue, oldValue)) {
      this._rawValue = newValue
      this._value = useDirectValue ? newValue : toReactive(newValue)
      if (__DEV__) {
        this.dep.trigger({
          target: this,
          type: TriggerOpTypes.SET,
          key: 'value',
          newValue,
          oldValue,
        })
      } else {
        this.dep.trigger()
      }
    }
  }
}

value 的 setter 方法:

  1. 获取旧值
  2. 判断是否直接使用新值(浅层响应式、新值是浅层或只读)
  3. 如果值发生变化,更新 _rawValue_value
  4. 触发依赖更新

triggerRef 函数

typescript 复制代码
/**
 * 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}
 */
export function triggerRef(ref: Ref): void {
  // ref may be an instance of ObjectRefImpl
  if ((ref as unknown as RefImpl).dep) {
    if (__DEV__) {
      ;(ref as unknown as RefImpl).dep.trigger({
        target: ref,
        type: TriggerOpTypes.SET,
        key: 'value',
        newValue: (ref as unknown as RefImpl)._value,
      })
    } else {
      ;(ref as unknown as RefImpl).dep.trigger()
    }
  }
}

triggerRef 函数用于手动触发浅层 ref 的依赖更新,通常在修改了浅层 ref 内部属性后使用。

类型定义

typescript 复制代码
export type MaybeRef<T = any> =
  | T
  | Ref<T>
  | ShallowRef<T>
  | WritableComputedRef<T>

export type MaybeRefOrGetter<T = any> = MaybeRef<T> | ComputedRef<T> | (() => T)

定义了两个常用的类型别名:

  • MaybeRef 表示可能是 ref 也可能不是的值
  • MaybeRefOrGetter 表示可能是 ref、只读计算属性或 getter 函数的值

unref 函数

typescript 复制代码
/**
 * 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}
 */
export function unref<T>(ref: MaybeRef<T> | ComputedRef<T>): T {
  return isRef(ref) ? ref.value : ref
}

unref 函数是 isRef(val) ? val.value : val 的语法糖,用于获取 ref 的值或直接返回非 ref 值。

toValue 函数

typescript 复制代码
/**
 * 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}
 */
export function toValue<T>(source: MaybeRefOrGetter<T>): T {
  return isFunction(source) ? source() : unref(source)
}

toValue 函数扩展了 unref 的功能,除了处理 ref 外还能处理 getter 函数。

proxyRefs 函数

typescript 复制代码
const shallowUnwrapHandlers: ProxyHandler<any> = {
  get: (target, key, receiver) =>
    key === ReactiveFlags.RAW
      ? target
      : 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)
    }
  },
}

定义了用于 proxyRefs 的代理处理器:

  • get 操作:如果是 RAW 标志则返回目标对象,否则对获取的值进行 unref 操作
  • set 操作:如果旧值是 ref 且新值不是 ref,则更新旧值 ref 的 value,否则直接设置属性
typescript 复制代码
/**
 * Returns a proxy for the given object that shallowly unwraps properties that
 * are refs. If the object already is reactive, it's returned as-is. If not, a
 * new reactive proxy is created.
 *
 * @param objectWithRefs - Either an already-reactive object or a simple object
 * that contains refs.
 */
export function proxyRefs<T extends object>(
  objectWithRefs: T,
): ShallowUnwrapRef<T> {
  return isReactive(objectWithRefs)
    ? objectWithRefs
    : new Proxy(objectWithRefs, shallowUnwrapHandlers)
}

proxyRefs 函数创建一个代理对象,该对象会自动解包属性中的 ref:

  • 如果对象已经是响应式的,直接返回
  • 否则创建一个使用 shallowUnwrapHandlers 处理器的代理

CustomRef 相关实现

typescript 复制代码
export type CustomRefFactory<T> = (
  track: () => void,
  trigger: () => void,
) => {
  get: () => T
  set: (value: T) => void
}

定义了 CustomRefFactory 类型,这是一个工厂函数类型,接收 track 和 trigger 函数作为参数,返回包含 get 和 set 方法的对象。

typescript 复制代码
class CustomRefImpl<T> {
  public dep: Dep

  private readonly _get: ReturnType<CustomRefFactory<T>>['get']
  private readonly _set: ReturnType<CustomRefFactory<T>>['set']

  public readonly [ReactiveFlags.IS_REF] = true

  public _value: T = undefined!

  constructor(factory: CustomRefFactory<T>) {
    const dep = (this.dep = new Dep())
    const { get, set } = factory(dep.track.bind(dep), dep.trigger.bind(dep))
    this._get = get
    this._set = set
  }

  get value() {
    return (this._value = this._get())
  }

  set value(newVal) {
    this._set(newVal)
  }
}

CustomRefImpl 是自定义 ref 的实现:

  • 通过工厂函数获取自定义的 get 和 set 方法
  • get 方法执行时会调用自定义的 get 方法并更新 _value
  • set 方法执行时会调用自定义的 set 方法
typescript 复制代码
/**
 * 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}
 */
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
  return new CustomRefImpl(factory) as any
}

customRef 函数用于创建自定义 ref,允许用户显式控制依赖追踪和更新触发。

toRefs 函数

typescript 复制代码
export type ToRefs<T = any> = {
  [K in keyof T]: ToRef<T[K]>
}

ToRefs 类型定义了将对象的所有属性转换为 ref 的类型。

typescript 复制代码
/**
 * 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}
 */
export function toRefs<T extends object>(object: T): ToRefs<T> {
  if (__DEV__ && !isProxy(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] = propertyToRef(object, key)
  }
  return ret
}

toRefs 函数将响应式对象的所有属性转换为 ref:

  • 开发环境下会检查对象是否为响应式对象
  • 根据对象是否为数组创建对应的返回容器
  • 遍历对象属性,使用 propertyToRef 将每个属性转换为 ref

ObjectRefImpl 类

typescript 复制代码
class ObjectRefImpl<T extends object, K extends keyof T> {
  public readonly [ReactiveFlags.IS_REF] = true
  public _value: T[K] = undefined!

  constructor(
    private readonly _object: T,
    private readonly _key: K,
    private readonly _defaultValue?: T[K],
  ) {}

  get value() {
    const val = this._object[this._key]
    return (this._value = val === undefined ? this._defaultValue! : val)
  }

  set value(newVal) {
    this._object[this._key] = newVal
  }

  get dep(): Dep | undefined {
    return getDepFromReactive(toRaw(this._object), this._key)
  }
}

ObjectRefImpl 是属性 ref 的实现:

  • 创建一个指向对象特定属性的 ref
  • get 操作返回对象对应属性的值
  • set 操作更新对象对应属性的值
  • dep 从原始对象的响应式系统中获取

GetterRefImpl 类

typescript 复制代码
class GetterRefImpl<T> {
  public readonly [ReactiveFlags.IS_REF] = true
  public readonly [ReactiveFlags.IS_READONLY] = true
  public _value: T = undefined!

  constructor(private readonly _getter: () => T) {}
  get value() {
    return (this._value = this._getter())
  }
}

GetterRefImpl 是 getter ref 的实现:

  • 创建一个只读的 ref,其值来自 getter 函数
  • 只有 get 操作,没有 set 操作

toRef 函数

typescript 复制代码
export type ToRef<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>

ToRef 类型定义了将值转换为 ref 的类型。

typescript 复制代码
/**
 * 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.
 *
 * @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
 * ```
 *
 * @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.
 * @see {@link https://vuejs.org/api/reactivity-utilities.html#toref}
 */
export function toRef<T>(
  value: T,
): T extends () => infer R
  ? Readonly<Ref<R>>
  : T extends Ref
    ? T
    : Ref<UnwrapRef<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(
  source: Record<string, any> | MaybeRef,
  key?: string,
  defaultValue?: unknown,
): Ref {
  if (isRef(source)) {
    return source
  } else if (isFunction(source)) {
    return new GetterRefImpl(source) as any
  } else if (isObject(source) && arguments.length > 1) {
    return propertyToRef(source, key!, defaultValue)
  } else {
    return ref(source)
  }
}

toRef 函数用于将值标准化为 ref:

  1. 如果是 ref,直接返回
  2. 如果是函数,创建 GetterRefImpl
  3. 如果是对象且提供了 key,使用 propertyToRef
  4. 否则创建普通 ref
typescript 复制代码
function propertyToRef(
  source: Record<string, any>,
  key: string,
  defaultValue?: unknown,
) {
  const val = source[key]
  return isRef(val)
    ? val
    : (new ObjectRefImpl(source, key, defaultValue) as any)
}

propertyToRef 函数用于创建属性 ref:

  • 如果属性值已经是 ref,直接返回
  • 否则创建 ObjectRefImpl 实例

类型定义

typescript 复制代码
/**
 * 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 {}

export type ShallowUnwrapRef<T> = {
  [K in keyof T]: DistributeRef<T[K]>
}

type DistributeRef<T> = T extends Ref<infer V, unknown> ? V : T

定义了 RefUnwrapBailTypes 接口和相关类型,允许其他包声明不应解包的类型。

typescript 复制代码
export type UnwrapRef<T> =
  T extends ShallowRef<infer V, unknown>
    ? V
    : T extends Ref<infer V, unknown>
      ? UnwrapRefSimple<V>
      : UnwrapRefSimple<T>

UnwrapRef 类型用于解包 ref 类型,获取其内部值的类型。

typescript 复制代码
export type UnwrapRefSimple<T> = T extends
  | Builtin
  | Ref
  | RefUnwrapBailTypes[keyof RefUnwrapBailTypes]
  | { [RawSymbol]?: true }
  ? T
  : T extends Map<infer K, infer V>
    ? Map<K, UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Map<any, any>>>
    : T extends WeakMap<infer K, infer V>
      ? WeakMap<K, UnwrapRefSimple<V>> &
          UnwrapRef<Omit<T, keyof WeakMap<any, any>>>
      : T extends Set<infer V>
        ? Set<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Set<any>>>
        : T extends WeakSet<infer V>
          ? WeakSet<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof WeakSet<any>>>
          : T extends ReadonlyArray<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

UnwrapRefSimple 类型递归解包复杂类型的 ref,处理各种内置对象类型和自定义对象类型。

TypeScript 语法解析

这个文件中使用了许多高级 TypeScript 语法和特性,下面是详细解析:

1. 泛型 (Generics)

typescript 复制代码
export interface Ref<T = any, S = T> {
  get value(): T
  set value(_: S)
  // ...
}

这里定义了 Ref 接口,使用了泛型参数 T 和 S,其中 S 默认值为 T。这允许 Ref 对象的 getter 和 setter 可以有不同的类型。

2. 条件类型 (Conditional Types)

typescript 复制代码
export function ref<T>(
  value: T,
): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T>

这个函数签名使用了条件类型,根据 T 是否继承自 Ref 来决定返回类型。如果 T 是 Ref 类型,则根据 IfAny 工具类型决定返回 Ref 还是 T;否则返回 Ref<UnwrapRef, UnwrapRef | T>。

3. 映射类型 (Mapped Types)

typescript 复制代码
export type ToRefs<T = any> = {
  [K in keyof T]: ToRef<T[K]>
}

这里使用了映射类型,将对象 T 的每个属性 K 映射为 ToRef<T[K]> 类型。

4. infer 关键字

typescript 复制代码
T extends () => infer R
  ? Readonly<Ref<R>>
  : T extends Ref
    ? T
    : Ref<UnwrapRef<T>>

在条件类型中使用 infer 关键字可以从函数类型中推断出返回值类型 R。

5. 模板字面量类型 (Template Literal Types)

虽然在这个文件中没有直接使用,但 Vue 项目中广泛使用了这种类型,用于创建更精确的类型。

6. 类型守卫 (Type Guards)

typescript 复制代码
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>

使用 r is Ref<T> 语法创建类型守卫函数,这在 TypeScript 中用于运行时类型检查。

7. 索引类型 (Indexed Types)

typescript 复制代码
class ObjectRefImpl<T extends object, K extends keyof T> {
  // ...
  get value() {
    const val = this._object[this._key]  // 使用索引类型访问属性
    return (this._value = val === undefined ? this._defaultValue! : val)
  }
}

通过 keyof TT[K] 语法实现对对象属性的类型安全访问。

8. 装饰器和访问修饰符

typescript 复制代码
class RefImpl<T = any> {
  _value: T
  private _rawValue: T

  dep: Dep = new Dep()

  public readonly [ReactiveFlags.IS_REF] = true
  public readonly [ReactiveFlags.IS_SHALLOW]: boolean = false
  // ...
}

使用了 public、private 和 readonly 等访问修饰符和属性初始化器。

9. 类型断言

typescript 复制代码
return new CustomRefImpl(factory) as any

在适当的时候使用类型断言来处理复杂的类型关系。

10. 联合类型和交叉类型

typescript 复制代码
export type MaybeRef<T = any> =
  | T
  | Ref<T>
  | ShallowRef<T>
  | WritableComputedRef<T>

使用联合类型表示一个值可能是多种类型中的一种。

11. 实用工具类型

文件中使用了多种 TypeScript 内置工具类型,如:

  • Partial<T> - 将 T 中的所有属性变为可选
  • Readonly<T> - 将 T 中的所有属性变为只读
  • Pick<T, K> - 从 T 中选择一组属性 K
  • Omit<T, K> - 从 T 中排除属性 K

12. 唯一符号 (unique symbol)

typescript 复制代码
declare const RefSymbol: unique symbol

使用 unique symbol 创建全局唯一的符号,用于类型系统中的唯一标识。

13. 模块增强 (Module Augmentation)

typescript 复制代码
/**
 * This is a special exported interface for other packages to declare
 * additional types that should bail out for ref unwrapping.
 */
export interface RefUnwrapBailTypes {}

定义了可以被其他模块扩展的接口,这是一种模块增强的模式。

14. 函数重载

typescript 复制代码
export function shallowRef<T>(
  value: T,
): Ref extends T
  ? T extends Ref
    ? IfAny<T, ShallowRef<T>, T>
    : ShallowRef<T>
  : ShallowRef<T>
export function shallowRef<T = any>(): ShallowRef<T | undefined>
export function shallowRef(value?: unknown) {
  return createRef(value, true)
}

通过函数重载提供多种调用方式,增强函数的类型安全性。

总结

这个文件实现了 Vue 3 响应式系统中的 ref 相关功能,包括:

  1. 基础的 refshallowRef 创建函数
  2. isRefunreftoReftoRefs 等工具函数
  3. triggerRefcustomRef 高级功能
  4. proxyRefstoValue 便利函数
  5. 复杂的类型系统支持 ref 的类型推导和解包
相关推荐
pepedd8641 小时前
还在开发vue2老项目吗?本文带你梳理vue版本区别
前端·vue.js·trae
前端缘梦1 小时前
深入理解 Vue 中的虚拟 DOM:原理与实战价值
前端·vue.js·面试
HWL56791 小时前
pnpm(Performant npm)的安装
前端·vue.js·npm·node.js
柯南95272 小时前
Vue 3 reactive.ts 源码理解
vue.js
小高0073 小时前
面试官:npm run build 到底干了什么?从 package.json 到 dist 的 7 步拆解
前端·javascript·vue.js
JayceM4 小时前
Vue中v-show与v-if的区别
前端·javascript·vue.js
HWL56794 小时前
“preinstall“: “npx only-allow pnpm“
运维·服务器·前端·javascript·vue.js
秃头小傻蛋4 小时前
Vue 项目中条件加载组件导致 CSS 样式丢失问题解决方案
前端·vue.js
复苏季风5 小时前
vite里把markdown文件渲染成vue组件
vue.js·markdown