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 extends WritableComputedRef { readonly value: T [ComputedRefSymbol]: true } export interface WritableComputedRef extends Ref { readonly effect: any /* Watcher */ } export type ComputedGetter = (...args: any[]) => T export type ComputedSetter = (v: T) => void export interface WritableComputedOptions { get: ComputedGetter set: ComputedSetter } export function computed( getter: ComputedGetter, debugOptions?: DebuggerOptions ): ComputedRef export function computed( options: WritableComputedOptions, debugOptions?: DebuggerOptions ): WritableComputedRef export function computed( getterOrOptions: ComputedGetter | WritableComputedOptions, debugOptions?: DebuggerOptions ) { let getter: ComputedGetter let setter: ComputedSetter 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 }