Browse Source

types(watch): better typing when watching multiple sources (#2425)

Zcating 5 years ago
parent
commit
d2d27b2e66
2 changed files with 34 additions and 9 deletions
  1. 16 5
      packages/runtime-core/src/apiWatch.ts
  2. 18 4
      test-dts/watch.test-d.ts

+ 16 - 5
packages/runtime-core/src/apiWatch.ts

@@ -78,15 +78,26 @@ export function watchEffect(
 // initial value for watchers to trigger on undefined initial values
 const INITIAL_WATCHER_VALUE = {}
 
+type MultiWatchSources = (WatchSource<unknown> | object)[]
+
 // overload #1: array of multiple sources + cb
-// Readonly constraint helps the callback to correctly infer value types based
-// on position in the source array. Otherwise the values will get a union type
-// of all possible value types.
 export function watch<
-  T extends Readonly<Array<WatchSource<unknown> | object>>,
+  T extends MultiWatchSources,
   Immediate extends Readonly<boolean> = false
 >(
-  sources: T,
+  sources: [...T],
+  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
+  options?: WatchOptions<Immediate>
+): WatchStopHandle
+
+// overload #2 for multiple sources w/ `as const`
+// watch([foo, bar] as const, () => {})
+// somehow [...T] breaks when the type is readonly
+export function watch<
+  T extends Readonly<MultiWatchSources>,
+  Immediate extends Readonly<boolean> = false
+>(
+  source: T,
   cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
   options?: WatchOptions<Immediate>
 ): WatchStopHandle

+ 18 - 4
test-dts/watch.test-d.ts

@@ -11,8 +11,8 @@ watch(source, (value, oldValue) => {
 })
 
 watch([source, source2, source3], (values, oldValues) => {
-  expectType<(string | number)[]>(values)
-  expectType<(string | number)[]>(oldValues)
+  expectType<[string, string, number]>(values)
+  expectType<[string, string, number]>(oldValues)
 })
 
 // const array
@@ -34,8 +34,10 @@ watch(
 watch(
   [source, source2, source3],
   (values, oldValues) => {
-    expectType<(string | number)[]>(values)
-    expectType<(string | number | undefined)[]>(oldValues)
+    expectType<[string, string, number]>(values)
+    expectType<[string | undefined, string | undefined, number | undefined]>(
+      oldValues
+    )
   },
   { immediate: true }
 )
@@ -61,3 +63,15 @@ watch(nestedRefSource, (v, ov) => {
   expectType<{ foo: number }>(v)
   expectType<{ foo: number }>(ov)
 })
+
+const someRef = ref({ test: 'test' })
+const otherRef = ref({ a: 'b' })
+watch([someRef, otherRef], values => {
+  const value1 = values[0]
+  // no type error
+  console.log(value1.test)
+
+  const value2 = values[1]
+  // no type error
+  console.log(value2.a)
+})