44 isRef ,
55 Ref ,
66 ComputedRef ,
7- ReactiveEffectOptions
7+ ReactiveEffectOptions ,
8+ isReactive
89} from '@vue/reactivity'
910import { queueJob } from './scheduler'
1011import {
@@ -80,14 +81,7 @@ export function watchEffect(
8081// initial value for watchers to trigger on undefined initial values
8182const INITIAL_WATCHER_VALUE = { }
8283
83- // overload #1: single source + cb
84- export function watch < T , Immediate extends Readonly < boolean > = false > (
85- source : WatchSource < T > ,
86- cb : WatchCallback < T , Immediate extends true ? ( T | undefined ) : T > ,
87- options ?: WatchOptions < Immediate >
88- ) : WatchStopHandle
89-
90- // overload #2: array of multiple sources + cb
84+ // overload #1: array of multiple sources + cb
9185// Readonly constraint helps the callback to correctly infer value types based
9286// on position in the source array. Otherwise the values will get a union type
9387// of all possible value types.
@@ -100,6 +94,23 @@ export function watch<
10094 options ?: WatchOptions < Immediate >
10195) : WatchStopHandle
10296
97+ // overload #2: single source + cb
98+ export function watch < T , Immediate extends Readonly < boolean > = false > (
99+ source : WatchSource < T > ,
100+ cb : WatchCallback < T , Immediate extends true ? ( T | undefined ) : T > ,
101+ options ?: WatchOptions < Immediate >
102+ ) : WatchStopHandle
103+
104+ // overload #3: watching reactive object w/ cb
105+ export function watch <
106+ T extends object ,
107+ Immediate extends Readonly < boolean > = false
108+ > (
109+ source : T ,
110+ cb : WatchCallback < T , Immediate extends true ? ( T | undefined ) : T > ,
111+ options ?: WatchOptions < Immediate >
112+ ) : WatchStopHandle
113+
103114// implementation
104115export function watch < T = any > (
105116 source : WatchSource < T > | WatchSource < T > [ ] ,
@@ -149,26 +160,39 @@ function doWatch(
149160 )
150161 } else if ( isRef ( source ) ) {
151162 getter = ( ) => source . value
152- } else if ( cb ) {
153- // getter with cb
154- getter = ( ) =>
155- callWithErrorHandling ( source , instance , ErrorCodes . WATCH_GETTER )
156- } else {
157- // no cb -> simple effect
158- getter = ( ) => {
159- if ( instance && instance . isUnmounted ) {
160- return
161- }
162- if ( cleanup ) {
163- cleanup ( )
163+ } else if ( isReactive ( source ) ) {
164+ getter = ( ) => source
165+ deep = true
166+ } else if ( isFunction ( source ) ) {
167+ if ( cb ) {
168+ // getter with cb
169+ getter = ( ) =>
170+ callWithErrorHandling ( source , instance , ErrorCodes . WATCH_GETTER )
171+ } else {
172+ // no cb -> simple effect
173+ getter = ( ) => {
174+ if ( instance && instance . isUnmounted ) {
175+ return
176+ }
177+ if ( cleanup ) {
178+ cleanup ( )
179+ }
180+ return callWithErrorHandling (
181+ source ,
182+ instance ,
183+ ErrorCodes . WATCH_CALLBACK ,
184+ [ onInvalidate ]
185+ )
164186 }
165- return callWithErrorHandling (
166- source ,
167- instance ,
168- ErrorCodes . WATCH_CALLBACK ,
169- [ onInvalidate ]
170- )
171187 }
188+ } else {
189+ getter = NOOP
190+ warn (
191+ `Invalid watch source: ` ,
192+ source ,
193+ `A watch source can only be a getter/effect function, a ref, ` +
194+ `a reactive object, or an array of these types.`
195+ )
172196 }
173197
174198 if ( cb && deep ) {
0 commit comments