ref.test-d.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import {
  2. Ref,
  3. ref,
  4. shallowRef,
  5. isRef,
  6. unref,
  7. reactive,
  8. expectType,
  9. proxyRefs,
  10. toRef,
  11. toRefs,
  12. ToRefs,
  13. shallowReactive,
  14. readonly,
  15. describe
  16. } from './index'
  17. function plainType(arg: number | Ref<number>) {
  18. // ref coercing
  19. const coerced = ref(arg)
  20. expectType<Ref<number>>(coerced)
  21. // isRef as type guard
  22. if (isRef(arg)) {
  23. expectType<Ref<number>>(arg)
  24. }
  25. // ref unwrapping
  26. expectType<number>(unref(arg))
  27. // ref inner type should be unwrapped
  28. const nestedRef = ref({
  29. foo: ref(1)
  30. })
  31. expectType<{ foo: number }>(nestedRef.value)
  32. // ref boolean
  33. const falseRef = ref(false)
  34. expectType<Ref<boolean>>(falseRef)
  35. expectType<boolean>(falseRef.value)
  36. // ref true
  37. const trueRef = ref<true>(true)
  38. expectType<Ref<true>>(trueRef)
  39. expectType<true>(trueRef.value)
  40. // tuple
  41. expectType<[number, string]>(unref(ref([1, '1'])))
  42. interface IteratorFoo {
  43. [Symbol.iterator]: any
  44. }
  45. // with symbol
  46. expectType<Ref<IteratorFoo | null | undefined>>(
  47. ref<IteratorFoo | null | undefined>()
  48. )
  49. // should not unwrap ref inside arrays
  50. const arr = ref([1, new Map<string, any>(), ref('1')]).value
  51. const value = arr[0]
  52. if (isRef(value)) {
  53. expectType<Ref>(value)
  54. } else if (typeof value === 'number') {
  55. expectType<number>(value)
  56. } else {
  57. // should narrow down to Map type
  58. // and not contain any Ref type
  59. expectType<Map<string, any>>(value)
  60. }
  61. // should still unwrap in objects nested in arrays
  62. const arr2 = ref([{ a: ref(1) }]).value
  63. expectType<number>(arr2[0].a)
  64. }
  65. plainType(1)
  66. function bailType(arg: HTMLElement | Ref<HTMLElement>) {
  67. // ref coercing
  68. const coerced = ref(arg)
  69. expectType<Ref<HTMLElement>>(coerced)
  70. // isRef as type guard
  71. if (isRef(arg)) {
  72. expectType<Ref<HTMLElement>>(arg)
  73. }
  74. // ref unwrapping
  75. expectType<HTMLElement>(unref(arg))
  76. // ref inner type should be unwrapped
  77. // eslint-disable-next-line no-restricted-globals
  78. const nestedRef = ref({ foo: ref(document.createElement('DIV')) })
  79. expectType<Ref<{ foo: HTMLElement }>>(nestedRef)
  80. expectType<{ foo: HTMLElement }>(nestedRef.value)
  81. }
  82. // eslint-disable-next-line no-restricted-globals
  83. const el = document.createElement('DIV')
  84. bailType(el)
  85. function withSymbol() {
  86. const customSymbol = Symbol()
  87. const obj = {
  88. [Symbol.asyncIterator]: ref(1),
  89. [Symbol.hasInstance]: { a: ref('a') },
  90. [Symbol.isConcatSpreadable]: { b: ref(true) },
  91. [Symbol.iterator]: [ref(1)],
  92. [Symbol.match]: new Set<Ref<number>>(),
  93. [Symbol.matchAll]: new Map<number, Ref<string>>(),
  94. [Symbol.replace]: { arr: [ref('a')] },
  95. [Symbol.search]: { set: new Set<Ref<number>>() },
  96. [Symbol.species]: { map: new Map<number, Ref<string>>() },
  97. [Symbol.split]: new WeakSet<Ref<boolean>>(),
  98. [Symbol.toPrimitive]: new WeakMap<Ref<boolean>, string>(),
  99. [Symbol.toStringTag]: { weakSet: new WeakSet<Ref<boolean>>() },
  100. [Symbol.unscopables]: { weakMap: new WeakMap<Ref<boolean>, string>() },
  101. [customSymbol]: { arr: [ref(1)] }
  102. }
  103. const objRef = ref(obj)
  104. expectType<Ref<number>>(objRef.value[Symbol.asyncIterator])
  105. expectType<{ a: Ref<string> }>(objRef.value[Symbol.hasInstance])
  106. expectType<{ b: Ref<boolean> }>(objRef.value[Symbol.isConcatSpreadable])
  107. expectType<Ref<number>[]>(objRef.value[Symbol.iterator])
  108. expectType<Set<Ref<number>>>(objRef.value[Symbol.match])
  109. expectType<Map<number, Ref<string>>>(objRef.value[Symbol.matchAll])
  110. expectType<{ arr: Ref<string>[] }>(objRef.value[Symbol.replace])
  111. expectType<{ set: Set<Ref<number>> }>(objRef.value[Symbol.search])
  112. expectType<{ map: Map<number, Ref<string>> }>(objRef.value[Symbol.species])
  113. expectType<WeakSet<Ref<boolean>>>(objRef.value[Symbol.split])
  114. expectType<WeakMap<Ref<boolean>, string>>(objRef.value[Symbol.toPrimitive])
  115. expectType<{ weakSet: WeakSet<Ref<boolean>> }>(
  116. objRef.value[Symbol.toStringTag]
  117. )
  118. expectType<{ weakMap: WeakMap<Ref<boolean>, string> }>(
  119. objRef.value[Symbol.unscopables]
  120. )
  121. expectType<{ arr: Ref<number>[] }>(objRef.value[customSymbol])
  122. }
  123. withSymbol()
  124. const state = reactive({
  125. foo: {
  126. value: 1,
  127. label: 'bar'
  128. }
  129. })
  130. expectType<string>(state.foo.label)
  131. // shallowRef
  132. type Status = 'initial' | 'ready' | 'invalidating'
  133. const shallowStatus = shallowRef<Status>('initial')
  134. if (shallowStatus.value === 'initial') {
  135. expectType<Ref<Status>>(shallowStatus)
  136. expectType<Status>(shallowStatus.value)
  137. shallowStatus.value = 'invalidating'
  138. }
  139. const refStatus = ref<Status>('initial')
  140. if (refStatus.value === 'initial') {
  141. expectType<Ref<Status>>(shallowStatus)
  142. expectType<Status>(shallowStatus.value)
  143. refStatus.value = 'invalidating'
  144. }
  145. // proxyRefs: should return `reactive` directly
  146. const r1 = reactive({
  147. k: 'v'
  148. })
  149. const p1 = proxyRefs(r1)
  150. expectType<typeof r1>(p1)
  151. // proxyRefs: `ShallowUnwrapRef`
  152. const r2 = {
  153. a: ref(1),
  154. obj: {
  155. k: ref('foo')
  156. }
  157. }
  158. const p2 = proxyRefs(r2)
  159. expectType<number>(p2.a)
  160. expectType<Ref<string>>(p2.obj.k)
  161. // toRef and toRefs
  162. {
  163. const obj: {
  164. a: number
  165. b: Ref<number>
  166. c: number | string
  167. } = {
  168. a: 1,
  169. b: ref(1),
  170. c: 1
  171. }
  172. // toRef
  173. expectType<Ref<number>>(toRef(obj, 'a'))
  174. expectType<Ref<number>>(toRef(obj, 'b'))
  175. // Should not distribute Refs over union
  176. expectType<Ref<number | string>>(toRef(obj, 'c'))
  177. // toRefs
  178. expectType<{
  179. a: Ref<number>
  180. b: Ref<number>
  181. // Should not distribute Refs over union
  182. c: Ref<number | string>
  183. }>(toRefs(obj))
  184. // Both should not do any unwrapping
  185. const someReactive = shallowReactive({
  186. a: {
  187. b: ref(42)
  188. }
  189. })
  190. const toRefResult = toRef(someReactive, 'a')
  191. const toRefsResult = toRefs(someReactive)
  192. expectType<Ref<number>>(toRefResult.value.b)
  193. expectType<Ref<number>>(toRefsResult.a.value.b)
  194. // #5188
  195. const props = { foo: 1 } as { foo: any }
  196. const { foo } = toRefs(props)
  197. expectType<Ref<any>>(foo)
  198. }
  199. // toRef default value
  200. {
  201. const obj: { x?: number } = {}
  202. const x = toRef(obj, 'x', 1)
  203. expectType<Ref<number>>(x)
  204. }
  205. // readonly() + ref()
  206. expectType<Readonly<Ref<number>>>(readonly(ref(1)))
  207. // #2687
  208. interface AppData {
  209. state: 'state1' | 'state2' | 'state3'
  210. }
  211. const data: ToRefs<AppData> = toRefs(
  212. reactive({
  213. state: 'state1'
  214. })
  215. )
  216. switch (data.state.value) {
  217. case 'state1':
  218. data.state.value = 'state2'
  219. break
  220. case 'state2':
  221. data.state.value = 'state3'
  222. break
  223. case 'state3':
  224. data.state.value = 'state1'
  225. break
  226. }
  227. // #3954
  228. function testUnrefGenerics<T>(p: T | Ref<T>) {
  229. expectType<T>(unref(p))
  230. }
  231. testUnrefGenerics(1)
  232. // #4771
  233. describe('shallow reactive in reactive', () => {
  234. const baz = reactive({
  235. foo: shallowReactive({
  236. a: {
  237. b: ref(42)
  238. }
  239. })
  240. })
  241. const foo = toRef(baz, 'foo')
  242. expectType<Ref<number>>(foo.value.a.b)
  243. expectType<number>(foo.value.a.b.value)
  244. })
  245. describe('shallow ref in reactive', () => {
  246. const x = reactive({
  247. foo: shallowRef({
  248. bar: {
  249. baz: ref(123),
  250. qux: reactive({
  251. z: ref(123)
  252. })
  253. }
  254. })
  255. })
  256. expectType<Ref<number>>(x.foo.bar.baz)
  257. expectType<number>(x.foo.bar.qux.z)
  258. })
  259. describe('ref in shallow ref', () => {
  260. const x = shallowRef({
  261. a: ref(123)
  262. })
  263. expectType<Ref<number>>(x.value.a)
  264. })
  265. describe('reactive in shallow ref', () => {
  266. const x = shallowRef({
  267. a: reactive({
  268. b: ref(0)
  269. })
  270. })
  271. expectType<number>(x.value.a.b)
  272. })