setupHelpers.test-d.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import {
  2. defineProps,
  3. defineEmits,
  4. useAttrs,
  5. useSlots,
  6. withDefaults,
  7. Slots,
  8. defineSlots,
  9. VNode
  10. } from 'vue'
  11. import { describe, expectType } from './utils'
  12. describe('defineProps w/ type declaration', () => {
  13. // type declaration
  14. const props = defineProps<{
  15. foo: string
  16. bool?: boolean
  17. boolAndUndefined: boolean | undefined
  18. }>()
  19. // explicitly declared type should be refined
  20. expectType<string>(props.foo)
  21. // @ts-expect-error
  22. props.bar
  23. expectType<boolean>(props.bool)
  24. expectType<boolean>(props.boolAndUndefined)
  25. })
  26. describe('defineProps w/ generics', () => {
  27. function test<T extends boolean>() {
  28. const props = defineProps<{ foo: T; bar: string; x?: boolean }>()
  29. expectType<T>(props.foo)
  30. expectType<string>(props.bar)
  31. expectType<boolean>(props.x)
  32. }
  33. test()
  34. })
  35. describe('defineProps w/ type declaration + withDefaults', () => {
  36. const res = withDefaults(
  37. defineProps<{
  38. number?: number
  39. arr?: string[]
  40. obj?: { x: number }
  41. fn?: (e: string) => void
  42. genStr?: string
  43. x?: string
  44. y?: string
  45. z?: string
  46. bool?: boolean
  47. boolAndUndefined: boolean | undefined
  48. }>(),
  49. {
  50. number: 123,
  51. arr: () => [],
  52. obj: () => ({ x: 123 }),
  53. fn: () => {},
  54. genStr: () => '',
  55. y: undefined,
  56. z: 'string'
  57. }
  58. )
  59. res.number + 1
  60. res.arr.push('hi')
  61. res.obj.x
  62. res.fn('hi')
  63. res.genStr.slice()
  64. // @ts-expect-error
  65. res.x.slice()
  66. // @ts-expect-error
  67. res.y.slice()
  68. expectType<string | undefined>(res.x)
  69. expectType<string | undefined>(res.y)
  70. expectType<string>(res.z)
  71. expectType<boolean>(res.bool)
  72. expectType<boolean>(res.boolAndUndefined)
  73. })
  74. describe('defineProps w/ union type declaration + withDefaults', () => {
  75. withDefaults(
  76. defineProps<{
  77. union1?: number | number[] | { x: number }
  78. union2?: number | number[] | { x: number }
  79. union3?: number | number[] | { x: number }
  80. union4?: number | number[] | { x: number }
  81. }>(),
  82. {
  83. union1: 123,
  84. union2: () => [123],
  85. union3: () => ({ x: 123 }),
  86. union4: () => 123
  87. }
  88. )
  89. })
  90. describe('defineProps w/ runtime declaration', () => {
  91. // runtime declaration
  92. const props = defineProps({
  93. foo: String,
  94. bar: {
  95. type: Number,
  96. default: 1
  97. },
  98. baz: {
  99. type: Array,
  100. required: true
  101. }
  102. })
  103. expectType<{
  104. foo?: string
  105. bar: number
  106. baz: unknown[]
  107. }>(props)
  108. props.foo && props.foo + 'bar'
  109. props.bar + 1
  110. // @ts-expect-error should be readonly
  111. props.bar++
  112. props.baz.push(1)
  113. const props2 = defineProps(['foo', 'bar'])
  114. props2.foo + props2.bar
  115. // @ts-expect-error
  116. props2.baz
  117. })
  118. describe('defineEmits w/ type declaration', () => {
  119. const emit = defineEmits<(e: 'change') => void>()
  120. emit('change')
  121. // @ts-expect-error
  122. emit()
  123. // @ts-expect-error
  124. emit('bar')
  125. type Emits = { (e: 'foo' | 'bar'): void; (e: 'baz', id: number): void }
  126. const emit2 = defineEmits<Emits>()
  127. emit2('foo')
  128. emit2('bar')
  129. emit2('baz', 123)
  130. // @ts-expect-error
  131. emit2('baz')
  132. })
  133. describe('defineEmits w/ alt type declaration', () => {
  134. const emit = defineEmits<{
  135. foo: [id: string]
  136. bar: any[]
  137. baz: []
  138. }>()
  139. emit('foo', 'hi')
  140. // @ts-expect-error
  141. emit('foo')
  142. emit('bar')
  143. emit('bar', 1, 2, 3)
  144. emit('baz')
  145. // @ts-expect-error
  146. emit('baz', 1)
  147. })
  148. describe('defineEmits w/ runtime declaration', () => {
  149. const emit = defineEmits({
  150. foo: () => {},
  151. bar: null
  152. })
  153. emit('foo')
  154. emit('bar', 123)
  155. // @ts-expect-error
  156. emit('baz')
  157. const emit2 = defineEmits(['foo', 'bar'])
  158. emit2('foo')
  159. emit2('bar', 123)
  160. // @ts-expect-error
  161. emit2('baz')
  162. })
  163. describe('defineSlots', () => {
  164. // short syntax
  165. const slots = defineSlots<{
  166. default: { foo: string; bar: number }
  167. optional?: string
  168. }>()
  169. expectType<(scope: { foo: string; bar: number }) => VNode[]>(slots.default)
  170. expectType<undefined | ((scope: string) => VNode[])>(slots.optional)
  171. // literal fn syntax (allow for specifying return type)
  172. const fnSlots = defineSlots<{
  173. default(props: { foo: string; bar: number }): any
  174. optional?(props: string): any
  175. }>()
  176. expectType<(scope: { foo: string; bar: number }) => VNode[]>(fnSlots.default)
  177. expectType<undefined | ((scope: string) => VNode[])>(fnSlots.optional)
  178. const slotsUntype = defineSlots()
  179. expectType<Slots>(slotsUntype)
  180. })
  181. describe('useAttrs', () => {
  182. const attrs = useAttrs()
  183. expectType<Record<string, unknown>>(attrs)
  184. })
  185. describe('useSlots', () => {
  186. const slots = useSlots()
  187. expectType<Slots>(slots)
  188. })