import { isServerRendering, noop, warn, def, isFunction } from 'core/util' import { Ref, RefFlag } from './ref' import Watcher from 'core/observer/watcher' import Dep from 'core/observer/dep' import { currentInstance } from '../currentInstance' import { ReactiveFlags } from './reactive' import { TrackOpTypes } from './operations' import { DebuggerOptions } from '../debug' declare const ComputedRefSymbol: unique symbol export interface ComputedRef<T = any> extends WritableComputedRef<T> { readonly value: T [ComputedRefSymbol]: true } export interface WritableComputedRef<T> extends Ref<T> { readonly effect: any /* Watcher */ } export type ComputedGetter<T> = (...args: any[]) => T export type ComputedSetter<T> = (v: T) => void export interface WritableComputedOptions<T> { get: ComputedGetter<T> set: ComputedSetter<T> } export function computed<T>( getter: ComputedGetter<T>, debugOptions?: DebuggerOptions ): ComputedRef<T> export function computed<T>( options: WritableComputedOptions<T>, debugOptions?: DebuggerOptions ): WritableComputedRef<T> export function computed<T>( getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>, debugOptions?: DebuggerOptions ) { let getter: ComputedGetter<T> let setter: ComputedSetter<T> const onlyGetter = isFunction(getterOrOptions) if (onlyGetter) { getter = getterOrOptions setter = __DEV__ ? () => { warn('Write operation failed: computed value is readonly') } : noop } else { getter = getterOrOptions.get setter = getterOrOptions.set } const watcher = isServerRendering() ? null : new Watcher(currentInstance, getter, noop, { lazy: true }) if (__DEV__ && watcher && debugOptions) { watcher.onTrack = debugOptions.onTrack watcher.onTrigger = debugOptions.onTrigger } const ref = { // some libs rely on the presence effect for checking computed refs // from normal refs, but the implementation doesn't matter effect: watcher, get value() { if (watcher) { if (watcher.dirty) { watcher.evaluate() } if (Dep.target) { if (__DEV__ && Dep.target.onTrack) { Dep.target.onTrack({ effect: Dep.target, target: ref, type: TrackOpTypes.GET, key: 'value' }) } watcher.depend() } return watcher.value } else { return getter() } }, set value(newVal) { setter(newVal) } } as any def(ref, RefFlag, true) def(ref, ReactiveFlags.IS_READONLY, onlyGetter) return ref }