From 42559dc5febd0dc4c53c3155a4cd90e58566d892 Mon Sep 17 00:00:00 2001 From: Evan You Date: Sun, 18 Aug 2019 22:49:08 -0400 Subject: [PATCH] types: watch API type overload --- packages/runtime-core/src/apiWatch.ts | 69 ++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index a92596f4..0f9e5186 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -17,19 +17,66 @@ export interface WatchOptions { onTrigger?: ReactiveEffectOptions['onTrigger'] } -type WatcherSource = Ref | (() => T) +type StopHandle = () => void + +type WatcherSource = Ref | (() => T) + +type MapSources = { + [K in keyof T]: T[K] extends WatcherSource ? V : never +} + +type CleanupRegistrator = (invalidate: () => void) => void + +type SimpleEffect = (onCleanup: CleanupRegistrator) => void const invoke = (fn: Function) => fn() +export function watch(effect: SimpleEffect, options?: WatchOptions): StopHandle + export function watch( - source: WatcherSource | WatcherSource[], - cb?: ( - newValue: V, - oldValue: V, - onInvalidate: (fn: () => void) => void - ) => any | void, - { lazy, flush, deep, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ -): () => void { + source: WatcherSource, + cb: (newValue: T, oldValue: T, onCleanup: CleanupRegistrator) => any, + options?: WatchOptions +): StopHandle + +export function watch[]>( + sources: T, + cb: ( + newValues: MapSources, + oldValues: MapSources, + onCleanup: CleanupRegistrator + ) => any, + options?: WatchOptions +): StopHandle + +// implementation +export function watch( + effectOrSource: + | WatcherSource + | WatcherSource[] + | SimpleEffect, + effectOrOptions?: + | ((value: any, oldValue: any, onCleanup: CleanupRegistrator) => any) + | WatchOptions, + options?: WatchOptions +): StopHandle { + if (typeof effectOrOptions === 'function') { + // effect callback as 2nd argument - this is a source watcher + return doWatch(effectOrSource, effectOrOptions, options) + } else { + // 2nd argument is either missing or an options object + // - this is a simple effect watcher + return doWatch(effectOrSource, null, effectOrOptions) + } +} + +function doWatch( + source: WatcherSource | WatcherSource[] | SimpleEffect, + cb: + | ((newValue: any, oldValue: any, onCleanup: CleanupRegistrator) => any) + | null, + { lazy, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ +): StopHandle { const scheduler = flush === 'sync' ? invoke : flush === 'pre' ? queueJob : queuePostFlushCb @@ -37,11 +84,11 @@ export function watch( ? () => source.map(s => (isRef(s) ? s.value : s())) : isRef(source) ? () => source.value - : source + : () => source(registerCleanup) const getter = deep ? () => traverse(baseGetter()) : baseGetter let cleanup: any - const registerCleanup = (fn: () => void) => { + const registerCleanup: CleanupRegistrator = (fn: () => void) => { // TODO wrap the cleanup fn for error handling cleanup = runner.onStop = fn }