setupHelpers.test-d.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. import {
  2. defineProps,
  3. defineEmits,
  4. useAttrs,
  5. useSlots,
  6. withDefaults,
  7. Slots,
  8. defineSlots,
  9. VNode,
  10. Ref,
  11. defineModel
  12. } from 'vue'
  13. import { describe, expectType } from './utils'
  14. import { defineComponent } from 'vue'
  15. import { useModel } from 'vue'
  16. describe('defineProps w/ type declaration', () => {
  17. // type declaration
  18. const props = defineProps<{
  19. foo: string
  20. bool?: boolean
  21. boolAndUndefined: boolean | undefined
  22. }>()
  23. // explicitly declared type should be refined
  24. expectType<string>(props.foo)
  25. // @ts-expect-error
  26. props.bar
  27. expectType<boolean>(props.bool)
  28. expectType<boolean>(props.boolAndUndefined)
  29. })
  30. describe('defineProps w/ generics', () => {
  31. function test<T extends boolean>() {
  32. const props = defineProps<{ foo: T; bar: string; x?: boolean }>()
  33. expectType<T>(props.foo)
  34. expectType<string>(props.bar)
  35. expectType<boolean>(props.x)
  36. }
  37. test()
  38. })
  39. describe('defineProps w/ type declaration + withDefaults', () => {
  40. const res = withDefaults(
  41. defineProps<{
  42. number?: number
  43. arr?: string[]
  44. obj?: { x: number }
  45. fn?: (e: string) => void
  46. genStr?: string
  47. x?: string
  48. y?: string
  49. z?: string
  50. bool?: boolean
  51. boolAndUndefined: boolean | undefined
  52. }>(),
  53. {
  54. number: 123,
  55. arr: () => [],
  56. obj: () => ({ x: 123 }),
  57. fn: () => {},
  58. genStr: () => '',
  59. y: undefined,
  60. z: 'string'
  61. }
  62. )
  63. res.number + 1
  64. res.arr.push('hi')
  65. res.obj.x
  66. res.fn('hi')
  67. res.genStr.slice()
  68. // @ts-expect-error
  69. res.x.slice()
  70. // @ts-expect-error
  71. res.y.slice()
  72. expectType<string | undefined>(res.x)
  73. expectType<string | undefined>(res.y)
  74. expectType<string>(res.z)
  75. expectType<boolean>(res.bool)
  76. expectType<boolean>(res.boolAndUndefined)
  77. })
  78. describe('defineProps w/ union type declaration + withDefaults', () => {
  79. withDefaults(
  80. defineProps<{
  81. union1?: number | number[] | { x: number }
  82. union2?: number | number[] | { x: number }
  83. union3?: number | number[] | { x: number }
  84. union4?: number | number[] | { x: number }
  85. }>(),
  86. {
  87. union1: 123,
  88. union2: () => [123],
  89. union3: () => ({ x: 123 }),
  90. union4: () => 123
  91. }
  92. )
  93. })
  94. describe('defineProps w/ generic type declaration + withDefaults', <T extends
  95. number, TA extends {
  96. a: string
  97. }, TString extends string>() => {
  98. const res = withDefaults(
  99. defineProps<{
  100. n?: number
  101. bool?: boolean
  102. generic1?: T[] | { x: T }
  103. generic2?: { x: T }
  104. generic3?: TString
  105. generic4?: TA
  106. }>(),
  107. {
  108. n: 123,
  109. generic1: () => [123, 33] as T[],
  110. generic2: () => ({ x: 123 }) as { x: T },
  111. generic3: () => 'test' as TString,
  112. generic4: () => ({ a: 'test' }) as TA
  113. }
  114. )
  115. res.n + 1
  116. expectType<T[] | { x: T }>(res.generic1)
  117. expectType<{ x: T }>(res.generic2)
  118. expectType<TString>(res.generic3)
  119. expectType<TA>(res.generic4)
  120. expectType<boolean>(res.bool)
  121. })
  122. describe('withDefaults w/ boolean type', () => {
  123. const res1 = withDefaults(
  124. defineProps<{
  125. bool?: boolean
  126. }>(),
  127. { bool: false }
  128. )
  129. expectType<boolean>(res1.bool)
  130. const res2 = withDefaults(
  131. defineProps<{
  132. bool?: boolean
  133. }>(),
  134. {
  135. bool: undefined
  136. }
  137. )
  138. expectType<boolean | undefined>(res2.bool)
  139. })
  140. describe('defineProps w/ runtime declaration', () => {
  141. // runtime declaration
  142. const props = defineProps({
  143. foo: String,
  144. bar: {
  145. type: Number,
  146. default: 1
  147. },
  148. baz: {
  149. type: Array,
  150. required: true
  151. }
  152. })
  153. expectType<{
  154. foo?: string
  155. bar: number
  156. baz: unknown[]
  157. }>(props)
  158. props.foo && props.foo + 'bar'
  159. props.bar + 1
  160. // @ts-expect-error should be readonly
  161. props.bar++
  162. props.baz.push(1)
  163. const props2 = defineProps(['foo', 'bar'])
  164. props2.foo + props2.bar
  165. // @ts-expect-error
  166. props2.baz
  167. })
  168. describe('defineEmits w/ type declaration', () => {
  169. const emit = defineEmits<(e: 'change') => void>()
  170. emit('change')
  171. // @ts-expect-error
  172. emit()
  173. // @ts-expect-error
  174. emit('bar')
  175. type Emits = { (e: 'foo' | 'bar'): void; (e: 'baz', id: number): void }
  176. const emit2 = defineEmits<Emits>()
  177. emit2('foo')
  178. emit2('bar')
  179. emit2('baz', 123)
  180. // @ts-expect-error
  181. emit2('baz')
  182. })
  183. describe('defineEmits w/ alt type declaration', () => {
  184. const emit = defineEmits<{
  185. foo: [id: string]
  186. bar: any[]
  187. baz: []
  188. }>()
  189. emit('foo', 'hi')
  190. // @ts-expect-error
  191. emit('foo')
  192. emit('bar')
  193. emit('bar', 1, 2, 3)
  194. emit('baz')
  195. // @ts-expect-error
  196. emit('baz', 1)
  197. })
  198. describe('defineEmits w/ runtime declaration', () => {
  199. const emit = defineEmits({
  200. foo: () => {},
  201. bar: null
  202. })
  203. emit('foo')
  204. emit('bar', 123)
  205. // @ts-expect-error
  206. emit('baz')
  207. const emit2 = defineEmits(['foo', 'bar'])
  208. emit2('foo')
  209. emit2('bar', 123)
  210. // @ts-expect-error
  211. emit2('baz')
  212. })
  213. describe('defineSlots', () => {
  214. // literal fn syntax (allow for specifying return type)
  215. const fnSlots = defineSlots<{
  216. default(props: { foo: string; bar: number }): any
  217. optional?(props: string): any
  218. }>()
  219. expectType<(scope: { foo: string; bar: number }) => VNode[]>(fnSlots.default)
  220. expectType<undefined | ((scope: string) => VNode[])>(fnSlots.optional)
  221. const slotsUntype = defineSlots()
  222. expectType<Slots>(slotsUntype)
  223. })
  224. describe('defineModel', () => {
  225. // overload 1
  226. const modelValueRequired = defineModel<boolean>({ required: true })
  227. expectType<Ref<boolean>>(modelValueRequired)
  228. // overload 2
  229. const modelValue = defineModel<string>()
  230. expectType<Ref<string | undefined>>(modelValue)
  231. modelValue.value = 'new value'
  232. const modelValueDefault = defineModel<boolean>({ default: true })
  233. expectType<Ref<boolean>>(modelValueDefault)
  234. // overload 3
  235. const countRequired = defineModel<number>('count', { required: false })
  236. expectType<Ref<number | undefined>>(countRequired)
  237. // overload 4
  238. const count = defineModel<number>('count')
  239. expectType<Ref<number | undefined>>(count)
  240. const countDefault = defineModel<number>('count', { default: 1 })
  241. expectType<Ref<number>>(countDefault)
  242. // infer type from default
  243. const inferred = defineModel({ default: 123 })
  244. expectType<Ref<number | undefined>>(inferred)
  245. const inferredRequired = defineModel({ default: 123, required: true })
  246. expectType<Ref<number>>(inferredRequired)
  247. // @ts-expect-error type / default mismatch
  248. defineModel<string>({ default: 123 })
  249. // @ts-expect-error unknown props option
  250. defineModel({ foo: 123 })
  251. // accept defineModel-only options
  252. defineModel({ local: true })
  253. defineModel('foo', { local: true })
  254. })
  255. describe('useModel', () => {
  256. defineComponent({
  257. props: ['foo'],
  258. setup(props) {
  259. const r = useModel(props, 'foo')
  260. expectType<Ref<any>>(r)
  261. // @ts-expect-error
  262. useModel(props, 'bar')
  263. }
  264. })
  265. defineComponent({
  266. props: {
  267. foo: String,
  268. bar: { type: Number, required: true },
  269. baz: { type: Boolean }
  270. },
  271. setup(props) {
  272. expectType<Ref<string | undefined>>(useModel(props, 'foo'))
  273. expectType<Ref<number>>(useModel(props, 'bar'))
  274. expectType<Ref<boolean>>(useModel(props, 'baz'))
  275. }
  276. })
  277. })
  278. describe('useAttrs', () => {
  279. const attrs = useAttrs()
  280. expectType<Record<string, unknown>>(attrs)
  281. })
  282. describe('useSlots', () => {
  283. const slots = useSlots()
  284. expectType<Slots>(slots)
  285. })