watch.test-d.ts 4.7 KB

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