watch.test-d.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import {
  2. type ComputedRef,
  3. type MaybeRef,
  4. type Ref,
  5. computed,
  6. defineComponent,
  7. defineModel,
  8. reactive,
  9. ref,
  10. shallowRef,
  11. watch,
  12. } from 'vue'
  13. import { expectType } from './utils'
  14. const source = ref('foo')
  15. const source2 = computed(() => source.value)
  16. const source3 = () => 1
  17. type Bar = Ref<string> | ComputedRef<string> | (() => number)
  18. type Foo = readonly [Ref<string>, ComputedRef<string>, () => number]
  19. type OnCleanup = (fn: () => void) => void
  20. const readonlyArr: Foo = [source, source2, source3]
  21. // lazy watcher will have consistent types for oldValue.
  22. watch(source, (value, oldValue, onCleanup) => {
  23. expectType<string>(value)
  24. expectType<string>(oldValue)
  25. expectType<OnCleanup>(onCleanup)
  26. })
  27. watch([source, source2, source3], (values, oldValues) => {
  28. expectType<[string, string, number]>(values)
  29. expectType<[string, string, number]>(oldValues)
  30. })
  31. // const array
  32. watch([source, source2, source3] as const, (values, oldValues) => {
  33. expectType<Readonly<[string, string, number]>>(values)
  34. expectType<Readonly<[string, string, number]>>(oldValues)
  35. })
  36. // reactive array
  37. watch(reactive([source, source2, source3]), (value, oldValues) => {
  38. expectType<Bar[]>(value)
  39. expectType<Bar[]>(oldValues)
  40. })
  41. // reactive w/ readonly tuple
  42. watch(reactive([source, source2, source3] as const), (value, oldValues) => {
  43. expectType<Foo>(value)
  44. expectType<Foo>(oldValues)
  45. })
  46. // readonly array
  47. watch(readonlyArr, (values, oldValues) => {
  48. expectType<Readonly<[string, string, number]>>(values)
  49. expectType<Readonly<[string, string, number]>>(oldValues)
  50. })
  51. // no type error, case from vueuse
  52. declare const aAny: any
  53. watch(aAny, (v, ov) => {})
  54. watch(aAny, (v, ov) => {}, { immediate: true })
  55. // immediate watcher's oldValue will be undefined on first run.
  56. watch(
  57. source,
  58. (value, oldValue) => {
  59. expectType<string>(value)
  60. expectType<string | undefined>(oldValue)
  61. },
  62. { immediate: true },
  63. )
  64. watch(
  65. [source, source2, source3],
  66. (values, oldValues) => {
  67. expectType<[string, string, number]>(values)
  68. expectType<[string | undefined, string | undefined, number | undefined]>(
  69. oldValues,
  70. )
  71. },
  72. { immediate: true },
  73. )
  74. // const array
  75. watch(
  76. [source, source2, source3] as const,
  77. (values, oldValues) => {
  78. expectType<Readonly<[string, string, number]>>(values)
  79. expectType<
  80. Readonly<[string | undefined, string | undefined, number | undefined]>
  81. >(oldValues)
  82. },
  83. { immediate: true },
  84. )
  85. // reactive array
  86. watch(
  87. reactive([source, source2, source3]),
  88. (value, oldVals) => {
  89. expectType<Bar[]>(value)
  90. expectType<Bar[] | undefined>(oldVals)
  91. },
  92. { immediate: true },
  93. )
  94. // reactive w/ readonly tuple
  95. watch(reactive([source, source2, source3] as const), (value, oldVals) => {
  96. expectType<Foo>(value)
  97. expectType<Foo | undefined>(oldVals)
  98. })
  99. // readonly array
  100. watch(
  101. readonlyArr,
  102. (values, oldValues) => {
  103. expectType<Readonly<[string, string, number]>>(values)
  104. expectType<
  105. Readonly<[string | undefined, string | undefined, number | undefined]>
  106. >(oldValues)
  107. },
  108. { immediate: true },
  109. )
  110. // should provide correct ref.value inner type to callbacks
  111. const nestedRefSource = ref({
  112. foo: ref(1),
  113. })
  114. watch(nestedRefSource, (v, ov) => {
  115. expectType<{ foo: number }>(v)
  116. expectType<{ foo: number }>(ov)
  117. })
  118. const someRef = ref({ test: 'test' })
  119. const otherRef = ref({ a: 'b' })
  120. watch([someRef, otherRef], values => {
  121. const value1 = values[0]
  122. // no type error
  123. console.log(value1.test)
  124. const value2 = values[1]
  125. // no type error
  126. console.log(value2.a)
  127. })
  128. // #6135
  129. defineComponent({
  130. data() {
  131. return { a: 1 }
  132. },
  133. created() {
  134. this.$watch(
  135. () => this.a,
  136. (v, ov, onCleanup) => {
  137. expectType<number>(v)
  138. expectType<number>(ov)
  139. expectType<OnCleanup>(onCleanup)
  140. },
  141. )
  142. },
  143. })
  144. {
  145. //#7852
  146. type Steps = { step: '1' } | { step: '2' }
  147. const shallowUnionGenParam = shallowRef<Steps>({ step: '1' })
  148. const shallowUnionAsCast = shallowRef({ step: '1' } as Steps)
  149. watch(shallowUnionGenParam, value => {
  150. expectType<Steps>(value)
  151. })
  152. watch(shallowUnionAsCast, value => {
  153. expectType<Steps>(value)
  154. })
  155. }
  156. {
  157. // defineModel
  158. const bool = defineModel({ default: false })
  159. watch(bool, value => {
  160. expectType<boolean>(value)
  161. })
  162. const bool1 = defineModel<boolean>()
  163. watch(bool1, value => {
  164. expectType<boolean | undefined>(value)
  165. })
  166. const msg = defineModel<string>({ required: true })
  167. watch(msg, value => {
  168. expectType<string>(value)
  169. })
  170. const arr = defineModel<string[]>({ required: true })
  171. watch(arr, value => {
  172. expectType<string[]>(value)
  173. })
  174. const obj = defineModel<{ foo: string }>({ required: true })
  175. watch(obj, value => {
  176. expectType<{ foo: string }>(value)
  177. })
  178. }
  179. {
  180. const css: MaybeRef<string> = ''
  181. watch(ref(css), value => {
  182. expectType<string>(value)
  183. })
  184. }