diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index f0445e87da0..20e0135c49a 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -86,6 +86,7 @@ export { traverse, onWatcherCleanup, WatchErrorCodes, + type MultiWatchSources, type WatchOptions, type WatchScheduler, type WatchStopHandle, diff --git a/packages/reactivity/src/watch.ts b/packages/reactivity/src/watch.ts index 648e6481b18..a2fa861e937 100644 --- a/packages/reactivity/src/watch.ts +++ b/packages/reactivity/src/watch.ts @@ -21,7 +21,7 @@ import { pauseTracking, resetTracking, } from './effect' -import { isReactive, isShallow } from './reactive' +import { type ReactiveMarker, isReactive, isShallow } from './reactive' import { type Ref, isRef } from './ref' import { getCurrentScope } from './effectScope' @@ -117,6 +117,65 @@ export function onWatcherCleanup( } } +type MaybeUndefined = I extends true ? T | undefined : T + +export type MultiWatchSources = (WatchSource | object)[] + +type MapSources = { + [K in keyof T]: T[K] extends WatchSource + ? MaybeUndefined + : T[K] extends object + ? MaybeUndefined + : never +} + +// overload: simple effect +export function watch = false>( + source: WatchEffect, + cb?: null, + options?: WatchOptions, +): WatchHandle + +// overload: single source + cb +export function watch = false>( + source: WatchSource, + cb: WatchCallback>, + options?: WatchOptions, +): WatchHandle + +// overload: reactive array or tuple of multiple sources + cb +export function watch< + T extends Readonly, + Immediate extends Readonly = false, +>( + sources: readonly [...T] | T, + cb: [T] extends [ReactiveMarker] + ? WatchCallback> + : WatchCallback, MapSources>, + options?: WatchOptions, +): WatchHandle + +// overload: array of multiple sources + cb +export function watch< + T extends MultiWatchSources, + Immediate extends Readonly = false, +>( + sources: [...T], + cb: WatchCallback, MapSources>, + options?: WatchOptions, +): WatchHandle + +// overload: watching reactive object w/ cb +export function watch< + T extends object, + Immediate extends Readonly = false, +>( + source: T, + cb: WatchCallback>, + options?: WatchOptions, +): WatchHandle + +// implementation export function watch( source: WatchSource | WatchSource[] | WatchEffect | object, cb?: WatchCallback | null, diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 8f6168cdf29..2ac3fe4feb8 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -1,6 +1,7 @@ import { type WatchOptions as BaseWatchOptions, type DebuggerOptions, + type MultiWatchSources, type ReactiveMarker, type WatchCallback, type WatchEffect, @@ -81,8 +82,6 @@ export function watchSyncEffect( ) } -export type MultiWatchSources = (WatchSource | object)[] - // overload: single source + cb export function watch = false>( source: WatchSource, @@ -223,7 +222,7 @@ function doWatch( } } - const watchHandle = baseWatch(source, cb, baseWatchOptions) + const watchHandle = baseWatch(source, cb as any, baseWatchOptions) if (__SSR__ && isInSSRComponentSetup) { if (ssrCleanup) { diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 9910f82102b..d853e8b2e85 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -224,9 +224,9 @@ export type { DebuggerEventExtraInfo, Raw, Reactive, + MultiWatchSources, } from '@vue/reactivity' export type { - MultiWatchSources, WatchEffect, WatchOptions, WatchEffectOptions as WatchOptionsBase,