defineComponent.test-d.tsx 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221
  1. import {
  2. type Component,
  3. type ComponentOptions,
  4. type ComponentPublicInstance,
  5. type PropType,
  6. type SetupContext,
  7. type Slots,
  8. type SlotsType,
  9. type VNode,
  10. createApp,
  11. defineComponent,
  12. h,
  13. reactive,
  14. ref,
  15. withKeys,
  16. withModifiers,
  17. } from 'vue'
  18. import { type IsAny, type IsUnion, describe, expectType } from './utils'
  19. describe('with object props', () => {
  20. interface ExpectedProps {
  21. a?: number | undefined
  22. aa: number
  23. aaa: number | null
  24. aaaa: number | undefined
  25. b: string
  26. e?: Function
  27. h: boolean
  28. j: undefined | (() => string | undefined)
  29. bb: string
  30. bbb: string
  31. bbbb: string | undefined
  32. bbbbb: string | undefined
  33. cc?: string[] | undefined
  34. dd: { n: 1 }
  35. ee?: () => string
  36. ff?: (a: number, b: string) => { a: boolean }
  37. ccc?: string[] | undefined
  38. ddd: string[]
  39. eee: () => { a: string }
  40. fff: (a: number, b: string) => { a: boolean }
  41. hhh: boolean
  42. ggg: 'foo' | 'bar'
  43. ffff: (a: number, b: string) => { a: boolean }
  44. iii?: (() => string) | (() => number)
  45. jjj: ((arg1: string) => string) | ((arg1: string, arg2: string) => string)
  46. kkk?: any
  47. validated?: string
  48. date?: Date
  49. l?: Date
  50. ll?: Date | number
  51. lll?: string | number
  52. }
  53. type GT = string & { __brand: unknown }
  54. const props = {
  55. a: Number,
  56. aa: {
  57. type: Number as PropType<number | undefined>,
  58. default: 1,
  59. },
  60. aaa: {
  61. type: Number as PropType<number | null>,
  62. default: 1,
  63. },
  64. aaaa: {
  65. type: Number as PropType<number | undefined>,
  66. // `as const` prevents widening to `boolean` (keeps literal `true` type)
  67. required: true as const,
  68. },
  69. // required should make property non-void
  70. b: {
  71. type: String,
  72. required: true as true,
  73. },
  74. e: Function,
  75. h: Boolean,
  76. j: Function as PropType<undefined | (() => string | undefined)>,
  77. // default value should infer type and make it non-void
  78. bb: {
  79. default: 'hello',
  80. },
  81. bbb: {
  82. // Note: default function value requires arrow syntax + explicit
  83. // annotation
  84. default: (props: any) => (props.bb as string) || 'foo',
  85. },
  86. bbbb: {
  87. type: String,
  88. default: undefined,
  89. },
  90. bbbbb: {
  91. type: String,
  92. default: () => undefined,
  93. },
  94. // explicit type casting
  95. cc: Array as PropType<string[]>,
  96. // required + type casting
  97. dd: {
  98. type: Object as PropType<{ n: 1 }>,
  99. required: true as true,
  100. },
  101. // return type
  102. ee: Function as PropType<() => string>,
  103. // arguments + object return
  104. ff: Function as PropType<(a: number, b: string) => { a: boolean }>,
  105. // explicit type casting with constructor
  106. ccc: Array as () => string[],
  107. // required + constructor type casting
  108. ddd: {
  109. type: Array as () => string[],
  110. required: true as true,
  111. },
  112. // required + object return
  113. eee: {
  114. type: Function as PropType<() => { a: string }>,
  115. required: true as true,
  116. },
  117. // required + arguments + object return
  118. fff: {
  119. type: Function as PropType<(a: number, b: string) => { a: boolean }>,
  120. required: true as true,
  121. },
  122. hhh: {
  123. type: Boolean,
  124. required: true as true,
  125. },
  126. // default + type casting
  127. ggg: {
  128. type: String as PropType<'foo' | 'bar'>,
  129. default: 'foo',
  130. },
  131. // default + function
  132. ffff: {
  133. type: Function as PropType<(a: number, b: string) => { a: boolean }>,
  134. default: (a: number, b: string) => ({ a: a > +b }),
  135. },
  136. // union + function with different return types
  137. iii: Function as PropType<(() => string) | (() => number)>,
  138. // union + function with different args & same return type
  139. jjj: {
  140. type: Function as PropType<
  141. ((arg1: string) => string) | ((arg1: string, arg2: string) => string)
  142. >,
  143. required: true as true,
  144. },
  145. kkk: null,
  146. validated: {
  147. type: String,
  148. // validator requires explicit annotation
  149. validator: (val: unknown) => val !== '',
  150. },
  151. date: Date,
  152. l: [Date],
  153. ll: [Date, Number],
  154. lll: [String, Number],
  155. }
  156. const MyComponent = defineComponent({
  157. props,
  158. setup(props) {
  159. // type assertion. See https://github.com/SamVerschueren/tsd
  160. expectType<ExpectedProps['a']>(props.a)
  161. expectType<ExpectedProps['aa']>(props.aa)
  162. expectType<ExpectedProps['aaa']>(props.aaa)
  163. // @ts-expect-error should included `undefined`
  164. expectType<number>(props.aaaa)
  165. expectType<ExpectedProps['aaaa']>(props.aaaa)
  166. expectType<ExpectedProps['b']>(props.b)
  167. expectType<ExpectedProps['e']>(props.e)
  168. expectType<ExpectedProps['h']>(props.h)
  169. expectType<ExpectedProps['j']>(props.j)
  170. expectType<ExpectedProps['bb']>(props.bb)
  171. expectType<ExpectedProps['bbb']>(props.bbb)
  172. expectType<ExpectedProps['bbbb']>(props.bbbb)
  173. expectType<ExpectedProps['bbbbb']>(props.bbbbb)
  174. expectType<ExpectedProps['cc']>(props.cc)
  175. expectType<ExpectedProps['dd']>(props.dd)
  176. expectType<ExpectedProps['ee']>(props.ee)
  177. expectType<ExpectedProps['ff']>(props.ff)
  178. expectType<ExpectedProps['ccc']>(props.ccc)
  179. expectType<ExpectedProps['ddd']>(props.ddd)
  180. expectType<ExpectedProps['eee']>(props.eee)
  181. expectType<ExpectedProps['fff']>(props.fff)
  182. expectType<ExpectedProps['hhh']>(props.hhh)
  183. expectType<ExpectedProps['ggg']>(props.ggg)
  184. expectType<ExpectedProps['ffff']>(props.ffff)
  185. if (typeof props.iii !== 'function') {
  186. expectType<undefined>(props.iii)
  187. }
  188. expectType<ExpectedProps['iii']>(props.iii)
  189. expectType<IsUnion<typeof props.jjj>>(true)
  190. expectType<ExpectedProps['jjj']>(props.jjj)
  191. expectType<ExpectedProps['kkk']>(props.kkk)
  192. expectType<ExpectedProps['validated']>(props.validated)
  193. expectType<ExpectedProps['date']>(props.date)
  194. expectType<ExpectedProps['l']>(props.l)
  195. expectType<ExpectedProps['ll']>(props.ll)
  196. expectType<ExpectedProps['lll']>(props.lll)
  197. // @ts-expect-error props should be readonly
  198. props.a = 1
  199. // setup context
  200. return {
  201. c: ref(1),
  202. d: {
  203. e: ref('hi'),
  204. },
  205. f: reactive({
  206. g: ref('hello' as GT),
  207. }),
  208. }
  209. },
  210. provide() {
  211. return {}
  212. },
  213. render() {
  214. const props = this.$props
  215. expectType<ExpectedProps['a']>(props.a)
  216. expectType<ExpectedProps['aa']>(props.aa)
  217. expectType<ExpectedProps['aaa']>(props.aaa)
  218. expectType<ExpectedProps['b']>(props.b)
  219. expectType<ExpectedProps['e']>(props.e)
  220. expectType<ExpectedProps['h']>(props.h)
  221. expectType<ExpectedProps['bb']>(props.bb)
  222. expectType<ExpectedProps['cc']>(props.cc)
  223. expectType<ExpectedProps['dd']>(props.dd)
  224. expectType<ExpectedProps['ee']>(props.ee)
  225. expectType<ExpectedProps['ff']>(props.ff)
  226. expectType<ExpectedProps['ccc']>(props.ccc)
  227. expectType<ExpectedProps['ddd']>(props.ddd)
  228. expectType<ExpectedProps['eee']>(props.eee)
  229. expectType<ExpectedProps['fff']>(props.fff)
  230. expectType<ExpectedProps['hhh']>(props.hhh)
  231. expectType<ExpectedProps['ggg']>(props.ggg)
  232. if (typeof props.iii !== 'function') {
  233. expectType<undefined>(props.iii)
  234. }
  235. expectType<ExpectedProps['iii']>(props.iii)
  236. expectType<IsUnion<typeof props.jjj>>(true)
  237. expectType<ExpectedProps['jjj']>(props.jjj)
  238. expectType<ExpectedProps['kkk']>(props.kkk)
  239. // @ts-expect-error props should be readonly
  240. props.a = 1
  241. // should also expose declared props on `this`
  242. expectType<ExpectedProps['a']>(this.a)
  243. expectType<ExpectedProps['aa']>(this.aa)
  244. expectType<ExpectedProps['aaa']>(this.aaa)
  245. expectType<ExpectedProps['b']>(this.b)
  246. expectType<ExpectedProps['e']>(this.e)
  247. expectType<ExpectedProps['h']>(this.h)
  248. expectType<ExpectedProps['bb']>(this.bb)
  249. expectType<ExpectedProps['cc']>(this.cc)
  250. expectType<ExpectedProps['dd']>(this.dd)
  251. expectType<ExpectedProps['ee']>(this.ee)
  252. expectType<ExpectedProps['ff']>(this.ff)
  253. expectType<ExpectedProps['ccc']>(this.ccc)
  254. expectType<ExpectedProps['ddd']>(this.ddd)
  255. expectType<ExpectedProps['eee']>(this.eee)
  256. expectType<ExpectedProps['fff']>(this.fff)
  257. expectType<ExpectedProps['hhh']>(this.hhh)
  258. expectType<ExpectedProps['ggg']>(this.ggg)
  259. if (typeof this.iii !== 'function') {
  260. expectType<undefined>(this.iii)
  261. }
  262. expectType<ExpectedProps['iii']>(this.iii)
  263. const { jjj } = this
  264. expectType<IsUnion<typeof jjj>>(true)
  265. expectType<ExpectedProps['jjj']>(this.jjj)
  266. expectType<ExpectedProps['kkk']>(this.kkk)
  267. // @ts-expect-error props on `this` should be readonly
  268. this.a = 1
  269. // assert setup context unwrapping
  270. expectType<number>(this.c)
  271. expectType<string>(this.d.e.value)
  272. expectType<GT>(this.f.g)
  273. // setup context properties should be mutable
  274. this.c = 2
  275. return null
  276. },
  277. })
  278. expectType<Component>(MyComponent)
  279. // Test TSX
  280. expectType<JSX.Element>(
  281. <MyComponent
  282. a={1}
  283. aaaa={1}
  284. b="b"
  285. bb="bb"
  286. e={() => {}}
  287. cc={['cc']}
  288. dd={{ n: 1 }}
  289. ee={() => 'ee'}
  290. ccc={['ccc']}
  291. ddd={['ddd']}
  292. eee={() => ({ a: 'eee' })}
  293. fff={(a, b) => ({ a: a > +b })}
  294. hhh={false}
  295. ggg="foo"
  296. jjj={() => ''}
  297. // should allow class/style as attrs
  298. class="bar"
  299. style={{ color: 'red' }}
  300. // should allow key
  301. key={'foo'}
  302. // should allow ref
  303. ref={'foo'}
  304. ref_for={true}
  305. />,
  306. )
  307. expectType<Component>(
  308. <MyComponent
  309. aaaa={1}
  310. b="b"
  311. dd={{ n: 1 }}
  312. ddd={['ddd']}
  313. eee={() => ({ a: 'eee' })}
  314. fff={(a, b) => ({ a: a > +b })}
  315. hhh={false}
  316. jjj={() => ''}
  317. />,
  318. )
  319. // @ts-expect-error missing required props
  320. let c = <MyComponent />
  321. // @ts-expect-error wrong prop types
  322. c = <MyComponent a={'wrong type'} b="foo" dd={{ n: 1 }} ddd={['foo']} />
  323. // @ts-expect-error wrong prop types
  324. c = <MyComponent ggg="baz" />
  325. // @ts-expect-error
  326. ;<MyComponent b="foo" dd={{ n: 'string' }} ddd={['foo']} />
  327. // `this` should be void inside of prop validators and prop default factories
  328. defineComponent({
  329. props: {
  330. myProp: {
  331. type: Number,
  332. validator(val: unknown): boolean {
  333. // @ts-expect-error
  334. return val !== this.otherProp
  335. },
  336. default(): number {
  337. // @ts-expect-error
  338. return this.otherProp + 1
  339. },
  340. },
  341. otherProp: {
  342. type: Number,
  343. required: true,
  344. },
  345. },
  346. })
  347. })
  348. describe('type inference w/ optional props declaration', () => {
  349. const MyComponent = defineComponent<{ a: string[]; msg: string }>({
  350. setup(props) {
  351. expectType<string>(props.msg)
  352. expectType<string[]>(props.a)
  353. return {
  354. b: 1,
  355. }
  356. },
  357. })
  358. expectType<JSX.Element>(<MyComponent msg="1" a={['1']} />)
  359. // @ts-expect-error
  360. ;<MyComponent />
  361. // @ts-expect-error
  362. ;<MyComponent msg="1" />
  363. })
  364. describe('type inference w/ direct setup function', () => {
  365. const MyComponent = defineComponent((_props: { msg: string }) => () => {})
  366. expectType<JSX.Element>(<MyComponent msg="foo" />)
  367. // @ts-expect-error
  368. ;<MyComponent />
  369. // @ts-expect-error
  370. ;<MyComponent msg={1} />
  371. })
  372. describe('type inference w/ array props declaration', () => {
  373. const MyComponent = defineComponent({
  374. props: ['a', 'b'],
  375. setup(props) {
  376. // @ts-expect-error props should be readonly
  377. props.a = 1
  378. expectType<any>(props.a)
  379. expectType<any>(props.b)
  380. return {
  381. c: 1,
  382. }
  383. },
  384. render() {
  385. expectType<any>(this.$props.a)
  386. expectType<any>(this.$props.b)
  387. // @ts-expect-error
  388. this.$props.a = 1
  389. expectType<any>(this.a)
  390. expectType<any>(this.b)
  391. expectType<number>(this.c)
  392. },
  393. })
  394. expectType<JSX.Element>(<MyComponent a={[1, 2]} b="b" />)
  395. // @ts-expect-error
  396. ;<MyComponent other="other" />
  397. })
  398. describe('type inference w/ options API', () => {
  399. defineComponent({
  400. props: { a: Number },
  401. setup() {
  402. return {
  403. b: 123,
  404. }
  405. },
  406. data() {
  407. // Limitation: we cannot expose the return result of setup() on `this`
  408. // here in data() - somehow that would mess up the inference
  409. expectType<number | undefined>(this.a)
  410. return {
  411. c: this.a || 123,
  412. someRef: ref(0),
  413. }
  414. },
  415. computed: {
  416. d() {
  417. expectType<number>(this.b)
  418. return this.b + 1
  419. },
  420. e: {
  421. get() {
  422. expectType<number>(this.b)
  423. expectType<number>(this.d)
  424. return this.b + this.d
  425. },
  426. set(v: number) {
  427. expectType<number>(this.b)
  428. expectType<number>(this.d)
  429. expectType<number>(v)
  430. },
  431. },
  432. },
  433. watch: {
  434. a() {
  435. expectType<number>(this.b)
  436. this.b + 1
  437. },
  438. },
  439. created() {
  440. // props
  441. expectType<number | undefined>(this.a)
  442. // returned from setup()
  443. expectType<number>(this.b)
  444. // returned from data()
  445. expectType<number>(this.c)
  446. // computed
  447. expectType<number>(this.d)
  448. // computed get/set
  449. expectType<number>(this.e)
  450. expectType<number>(this.someRef)
  451. },
  452. methods: {
  453. doSomething() {
  454. // props
  455. expectType<number | undefined>(this.a)
  456. // returned from setup()
  457. expectType<number>(this.b)
  458. // returned from data()
  459. expectType<number>(this.c)
  460. // computed
  461. expectType<number>(this.d)
  462. // computed get/set
  463. expectType<number>(this.e)
  464. },
  465. returnSomething() {
  466. return this.a
  467. },
  468. },
  469. render() {
  470. // props
  471. expectType<number | undefined>(this.a)
  472. // returned from setup()
  473. expectType<number>(this.b)
  474. // returned from data()
  475. expectType<number>(this.c)
  476. // computed
  477. expectType<number>(this.d)
  478. // computed get/set
  479. expectType<number>(this.e)
  480. // method
  481. expectType<() => number | undefined>(this.returnSomething)
  482. },
  483. })
  484. })
  485. // #4051
  486. describe('type inference w/ empty prop object', () => {
  487. const MyComponent = defineComponent({
  488. props: {},
  489. setup(props) {
  490. return {}
  491. },
  492. render() {},
  493. })
  494. expectType<JSX.Element>(<MyComponent />)
  495. // AllowedComponentProps
  496. expectType<JSX.Element>(<MyComponent class={'foo'} />)
  497. // ComponentCustomProps
  498. expectType<JSX.Element>(<MyComponent custom={1} />)
  499. // VNodeProps
  500. expectType<JSX.Element>(<MyComponent key="1" />)
  501. // @ts-expect-error
  502. expectError(<MyComponent other="other" />)
  503. })
  504. describe('with mixins', () => {
  505. const MixinA = defineComponent({
  506. emits: ['bar'],
  507. props: {
  508. aP1: {
  509. type: String,
  510. default: 'aP1',
  511. },
  512. aP2: Boolean,
  513. },
  514. data() {
  515. return {
  516. a: 1,
  517. }
  518. },
  519. })
  520. const MixinB = defineComponent({
  521. props: ['bP1', 'bP2'],
  522. data() {
  523. return {
  524. b: 2,
  525. }
  526. },
  527. })
  528. const MixinC = defineComponent({
  529. data() {
  530. return {
  531. c: 3,
  532. }
  533. },
  534. })
  535. const MixinD = defineComponent({
  536. mixins: [MixinA],
  537. data() {
  538. //@ts-expect-error computed are not available on data()
  539. expectError<number>(this.dC1)
  540. //@ts-expect-error computed are not available on data()
  541. expectError<string>(this.dC2)
  542. return {
  543. d: 4,
  544. }
  545. },
  546. setup(props) {
  547. expectType<string>(props.aP1)
  548. },
  549. computed: {
  550. dC1() {
  551. return this.d + this.a
  552. },
  553. dC2() {
  554. return this.aP1 + 'dC2'
  555. },
  556. },
  557. })
  558. const MyComponent = defineComponent({
  559. mixins: [MixinA, MixinB, MixinC, MixinD],
  560. emits: ['click'],
  561. props: {
  562. // required should make property non-void
  563. z: {
  564. type: String,
  565. required: true,
  566. },
  567. },
  568. data(vm) {
  569. expectType<number>(vm.a)
  570. expectType<number>(vm.b)
  571. expectType<number>(vm.c)
  572. expectType<number>(vm.d)
  573. // should also expose declared props on `this`
  574. expectType<number>(this.a)
  575. expectType<string>(this.aP1)
  576. expectType<boolean | undefined>(this.aP2)
  577. expectType<number>(this.b)
  578. expectType<any>(this.bP1)
  579. expectType<number>(this.c)
  580. expectType<number>(this.d)
  581. return {}
  582. },
  583. setup(props) {
  584. expectType<string>(props.z)
  585. // props
  586. expectType<((...args: any[]) => any) | undefined>(props.onClick)
  587. // from MixinA
  588. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  589. expectType<string>(props.aP1)
  590. expectType<boolean | undefined>(props.aP2)
  591. expectType<any>(props.bP1)
  592. expectType<any>(props.bP2)
  593. expectType<string>(props.z)
  594. },
  595. render() {
  596. const props = this.$props
  597. // props
  598. expectType<((...args: any[]) => any) | undefined>(props.onClick)
  599. // from MixinA
  600. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  601. expectType<string>(props.aP1)
  602. expectType<boolean | undefined>(props.aP2)
  603. expectType<any>(props.bP1)
  604. expectType<any>(props.bP2)
  605. expectType<string>(props.z)
  606. const data = this.$data
  607. expectType<number>(data.a)
  608. expectType<number>(data.b)
  609. expectType<number>(data.c)
  610. expectType<number>(data.d)
  611. // should also expose declared props on `this`
  612. expectType<number>(this.a)
  613. expectType<string>(this.aP1)
  614. expectType<boolean | undefined>(this.aP2)
  615. expectType<number>(this.b)
  616. expectType<any>(this.bP1)
  617. expectType<number>(this.c)
  618. expectType<number>(this.d)
  619. expectType<number>(this.dC1)
  620. expectType<string>(this.dC2)
  621. // props should be readonly
  622. // @ts-expect-error
  623. this.aP1 = 'new'
  624. // @ts-expect-error
  625. this.z = 1
  626. // props on `this` should be readonly
  627. // @ts-expect-error
  628. this.bP1 = 1
  629. // string value can not assigned to number type value
  630. // @ts-expect-error
  631. this.c = '1'
  632. // setup context properties should be mutable
  633. this.d = 5
  634. return null
  635. },
  636. })
  637. // Test TSX
  638. expectType<JSX.Element>(
  639. <MyComponent aP1={'aP'} aP2 bP1={1} bP2={[1, 2]} z={'z'} />,
  640. )
  641. // missing required props
  642. // @ts-expect-error
  643. ;<MyComponent />
  644. // wrong prop types
  645. // @ts-expect-error
  646. ;<MyComponent aP1="ap" aP2={'wrong type'} bP1="b" z={'z'} />
  647. // @ts-expect-error
  648. ;<MyComponent aP1={1} bP2={[1]} />
  649. })
  650. describe('with extends', () => {
  651. const Base = defineComponent({
  652. props: {
  653. aP1: Boolean,
  654. aP2: {
  655. type: Number,
  656. default: 2,
  657. },
  658. },
  659. data() {
  660. return {
  661. a: 1,
  662. }
  663. },
  664. computed: {
  665. c(): number {
  666. return this.aP2 + this.a
  667. },
  668. },
  669. })
  670. const MyComponent = defineComponent({
  671. extends: Base,
  672. props: {
  673. // required should make property non-void
  674. z: {
  675. type: String,
  676. required: true,
  677. },
  678. },
  679. render() {
  680. const props = this.$props
  681. // props
  682. expectType<boolean | undefined>(props.aP1)
  683. expectType<number>(props.aP2)
  684. expectType<string>(props.z)
  685. const data = this.$data
  686. expectType<number>(data.a)
  687. // should also expose declared props on `this`
  688. expectType<number>(this.a)
  689. expectType<boolean | undefined>(this.aP1)
  690. expectType<number>(this.aP2)
  691. // setup context properties should be mutable
  692. this.a = 5
  693. return null
  694. },
  695. })
  696. // Test TSX
  697. expectType<JSX.Element>(<MyComponent aP2={3} aP1 z={'z'} />)
  698. // missing required props
  699. // @ts-expect-error
  700. ;<MyComponent />
  701. // wrong prop types
  702. // @ts-expect-error
  703. ;<MyComponent aP2={'wrong type'} z={'z'} />
  704. // @ts-expect-error
  705. ;<MyComponent aP1={3} />
  706. })
  707. describe('extends with mixins', () => {
  708. const Mixin = defineComponent({
  709. emits: ['bar'],
  710. props: {
  711. mP1: {
  712. type: String,
  713. default: 'mP1',
  714. },
  715. mP2: Boolean,
  716. mP3: {
  717. type: Boolean,
  718. required: true,
  719. },
  720. },
  721. data() {
  722. return {
  723. a: 1,
  724. }
  725. },
  726. })
  727. const Base = defineComponent({
  728. emits: ['foo'],
  729. props: {
  730. p1: Boolean,
  731. p2: {
  732. type: Number,
  733. default: 2,
  734. },
  735. p3: {
  736. type: Boolean,
  737. required: true,
  738. },
  739. },
  740. data() {
  741. return {
  742. b: 2,
  743. }
  744. },
  745. computed: {
  746. c(): number {
  747. return this.p2 + this.b
  748. },
  749. },
  750. })
  751. const MyComponent = defineComponent({
  752. extends: Base,
  753. mixins: [Mixin],
  754. emits: ['click'],
  755. props: {
  756. // required should make property non-void
  757. z: {
  758. type: String,
  759. required: true,
  760. },
  761. },
  762. render() {
  763. const props = this.$props
  764. // props
  765. expectType<((...args: any[]) => any) | undefined>(props.onClick)
  766. // from Mixin
  767. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  768. // from Base
  769. expectType<((...args: any[]) => any) | undefined>(props.onFoo)
  770. expectType<boolean | undefined>(props.p1)
  771. expectType<number>(props.p2)
  772. expectType<string>(props.z)
  773. expectType<string>(props.mP1)
  774. expectType<boolean | undefined>(props.mP2)
  775. const data = this.$data
  776. expectType<number>(data.a)
  777. expectType<number>(data.b)
  778. // should also expose declared props on `this`
  779. expectType<number>(this.a)
  780. expectType<number>(this.b)
  781. expectType<boolean | undefined>(this.p1)
  782. expectType<number>(this.p2)
  783. expectType<string>(this.mP1)
  784. expectType<boolean | undefined>(this.mP2)
  785. // setup context properties should be mutable
  786. this.a = 5
  787. return null
  788. },
  789. })
  790. // Test TSX
  791. expectType<JSX.Element>(<MyComponent mP1="p1" mP2 mP3 p1 p2={1} p3 z={'z'} />)
  792. // mP1, mP2, p1, and p2 have default value. these are not required
  793. expectType<JSX.Element>(<MyComponent mP3 p3 z={'z'} />)
  794. // missing required props
  795. // @ts-expect-error
  796. ;<MyComponent mP3 p3 /* z='z' */ />
  797. // missing required props from mixin
  798. // @ts-expect-error
  799. ;<MyComponent /* mP3 */ p3 z="z" />
  800. // missing required props from extends
  801. // @ts-expect-error
  802. ;<MyComponent mP3 /* p3 */ z="z" />
  803. // wrong prop types
  804. // @ts-expect-error
  805. ;<MyComponent p2={'wrong type'} z={'z'} />
  806. // @ts-expect-error
  807. ;<MyComponent mP1={3} />
  808. // #3468
  809. const CompWithD = defineComponent({
  810. data() {
  811. return { foo: 1 }
  812. },
  813. })
  814. const CompWithC = defineComponent({
  815. computed: {
  816. foo() {
  817. return 1
  818. },
  819. },
  820. })
  821. const CompWithM = defineComponent({ methods: { foo() {} } })
  822. const CompEmpty = defineComponent({})
  823. defineComponent({
  824. mixins: [CompWithD, CompEmpty],
  825. mounted() {
  826. expectType<number>(this.foo)
  827. },
  828. })
  829. defineComponent({
  830. mixins: [CompWithC, CompEmpty],
  831. mounted() {
  832. expectType<number>(this.foo)
  833. },
  834. })
  835. defineComponent({
  836. mixins: [CompWithM, CompEmpty],
  837. mounted() {
  838. expectType<() => void>(this.foo)
  839. },
  840. })
  841. })
  842. describe('compatibility w/ createApp', () => {
  843. const comp = defineComponent({})
  844. createApp(comp).mount('#hello')
  845. const comp2 = defineComponent({
  846. props: { foo: String },
  847. })
  848. createApp(comp2).mount('#hello')
  849. const comp3 = defineComponent({
  850. setup() {
  851. return {
  852. a: 1,
  853. }
  854. },
  855. })
  856. createApp(comp3).mount('#hello')
  857. })
  858. describe('defineComponent', () => {
  859. describe('should accept components defined with defineComponent', () => {
  860. const comp = defineComponent({})
  861. defineComponent({
  862. components: { comp },
  863. })
  864. })
  865. describe('should accept class components with receiving constructor arguments', () => {
  866. class Comp {
  867. static __vccOpts = {}
  868. constructor(_props: { foo: string }) {}
  869. }
  870. defineComponent({
  871. components: { Comp },
  872. })
  873. })
  874. })
  875. describe('emits', () => {
  876. // Note: for TSX inference, ideally we want to map emits to onXXX props,
  877. // but that requires type-level string constant concatenation as suggested in
  878. // https://github.com/Microsoft/TypeScript/issues/12754
  879. // The workaround for TSX users is instead of using emits, declare onXXX props
  880. // and call them instead. Since `v-on:click` compiles to an `onClick` prop,
  881. // this would also support other users consuming the component in templates
  882. // with `v-on` listeners.
  883. // with object emits
  884. defineComponent({
  885. emits: {
  886. click: (n: number) => typeof n === 'number',
  887. input: (b: string) => b.length > 1,
  888. Focus: (f: boolean) => !!f,
  889. },
  890. setup(props, { emit }) {
  891. expectType<((n: number) => boolean) | undefined>(props.onClick)
  892. expectType<((b: string) => boolean) | undefined>(props.onInput)
  893. expectType<((f: boolean) => boolean) | undefined>(props.onFocus)
  894. emit('click', 1)
  895. emit('input', 'foo')
  896. emit('Focus', true)
  897. // @ts-expect-error
  898. emit('nope')
  899. // @ts-expect-error
  900. emit('click')
  901. // @ts-expect-error
  902. emit('click', 'foo')
  903. // @ts-expect-error
  904. emit('input')
  905. // @ts-expect-error
  906. emit('input', 1)
  907. // @ts-expect-error
  908. emit('focus')
  909. // @ts-expect-error
  910. emit('focus', true)
  911. },
  912. created() {
  913. this.$emit('click', 1)
  914. this.$emit('input', 'foo')
  915. // @ts-expect-error
  916. this.$emit('nope')
  917. // @ts-expect-error
  918. this.$emit('click')
  919. // @ts-expect-error
  920. this.$emit('click', 'foo')
  921. // @ts-expect-error
  922. this.$emit('input')
  923. // @ts-expect-error
  924. this.$emit('input', 1)
  925. // @ts-expect-error
  926. this.$emit('focus')
  927. // @ts-expect-error
  928. this.$emit('focus', true)
  929. },
  930. mounted() {
  931. // #3599
  932. this.$nextTick(function () {
  933. // this should be bound to this instance
  934. this.$emit('click', 1)
  935. this.$emit('input', 'foo')
  936. // @ts-expect-error
  937. this.$emit('nope')
  938. // @ts-expect-error
  939. this.$emit('click')
  940. // @ts-expect-error
  941. this.$emit('click', 'foo')
  942. // @ts-expect-error
  943. this.$emit('input')
  944. // @ts-expect-error
  945. this.$emit('input', 1)
  946. // @ts-expect-error
  947. this.$emit('focus')
  948. // @ts-expect-error
  949. this.$emit('focus', true)
  950. })
  951. },
  952. })
  953. // with array emits
  954. defineComponent({
  955. emits: ['foo', 'bar'],
  956. setup(props, { emit }) {
  957. expectType<((...args: any[]) => any) | undefined>(props.onFoo)
  958. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  959. emit('foo')
  960. emit('foo', 123)
  961. emit('bar')
  962. // @ts-expect-error
  963. emit('nope')
  964. },
  965. created() {
  966. this.$emit('foo')
  967. this.$emit('foo', 123)
  968. this.$emit('bar')
  969. // @ts-expect-error
  970. this.$emit('nope')
  971. },
  972. })
  973. // with tsx
  974. const Component = defineComponent({
  975. emits: {
  976. click: (n: number) => typeof n === 'number',
  977. },
  978. setup(props, { emit }) {
  979. expectType<((n: number) => any) | undefined>(props.onClick)
  980. emit('click', 1)
  981. // @ts-expect-error
  982. emit('click')
  983. // @ts-expect-error
  984. emit('click', 'foo')
  985. },
  986. })
  987. defineComponent({
  988. render() {
  989. return (
  990. <Component
  991. onClick={(n: number) => {
  992. return n + 1
  993. }}
  994. />
  995. )
  996. },
  997. })
  998. // #11803 manual props annotation in setup()
  999. const Hello = defineComponent({
  1000. name: 'HelloWorld',
  1001. inheritAttrs: false,
  1002. props: { foo: String },
  1003. emits: {
  1004. customClick: (args: string) => typeof args === 'string',
  1005. },
  1006. setup(props: { foo?: string }) {},
  1007. })
  1008. ;<Hello onCustomClick={() => {}} />
  1009. // without emits
  1010. defineComponent({
  1011. setup(props, { emit }) {
  1012. emit('test', 1)
  1013. emit('test')
  1014. },
  1015. })
  1016. // emit should be valid when ComponentPublicInstance is used.
  1017. const instance = {} as ComponentPublicInstance
  1018. instance.$emit('test', 1)
  1019. instance.$emit('test')
  1020. // `this` should be void inside of emits validators
  1021. defineComponent({
  1022. props: ['bar'],
  1023. emits: {
  1024. foo(): boolean {
  1025. // @ts-expect-error
  1026. return this.bar === 3
  1027. },
  1028. },
  1029. })
  1030. })
  1031. describe('inject', () => {
  1032. // with object inject
  1033. defineComponent({
  1034. props: {
  1035. a: String,
  1036. },
  1037. inject: {
  1038. foo: 'foo',
  1039. bar: 'bar',
  1040. },
  1041. created() {
  1042. expectType<unknown>(this.foo)
  1043. expectType<unknown>(this.bar)
  1044. // @ts-expect-error
  1045. this.foobar = 1
  1046. },
  1047. })
  1048. // with array inject
  1049. defineComponent({
  1050. props: ['a', 'b'],
  1051. inject: ['foo', 'bar'],
  1052. created() {
  1053. expectType<unknown>(this.foo)
  1054. expectType<unknown>(this.bar)
  1055. // @ts-expect-error
  1056. this.foobar = 1
  1057. },
  1058. })
  1059. // with no props
  1060. defineComponent({
  1061. inject: {
  1062. foo: {
  1063. from: 'pfoo',
  1064. default: 'foo',
  1065. },
  1066. bar: {
  1067. from: 'pbar',
  1068. default: 'bar',
  1069. },
  1070. },
  1071. created() {
  1072. expectType<unknown>(this.foo)
  1073. expectType<unknown>(this.bar)
  1074. // @ts-expect-error
  1075. this.foobar = 1
  1076. },
  1077. })
  1078. // without inject
  1079. defineComponent({
  1080. props: ['a', 'b'],
  1081. created() {
  1082. // @ts-expect-error
  1083. this.foo = 1
  1084. // @ts-expect-error
  1085. this.bar = 1
  1086. },
  1087. })
  1088. })
  1089. describe('componentOptions setup should be `SetupContext`', () => {
  1090. expectType<ComponentOptions['setup']>(
  1091. {} as (props: Record<string, any>, ctx: SetupContext) => any,
  1092. )
  1093. })
  1094. describe('extract instance type', () => {
  1095. const Base = defineComponent({
  1096. props: {
  1097. baseA: {
  1098. type: Number,
  1099. default: 1,
  1100. },
  1101. },
  1102. })
  1103. const MixinA = defineComponent({
  1104. props: {
  1105. mA: {
  1106. type: String,
  1107. default: '',
  1108. },
  1109. },
  1110. })
  1111. const CompA = defineComponent({
  1112. extends: Base,
  1113. mixins: [MixinA],
  1114. props: {
  1115. a: {
  1116. type: Boolean,
  1117. default: false,
  1118. },
  1119. b: {
  1120. type: String,
  1121. required: true,
  1122. },
  1123. c: Number,
  1124. },
  1125. })
  1126. const compA = {} as InstanceType<typeof CompA>
  1127. expectType<boolean>(compA.a)
  1128. expectType<string>(compA.b)
  1129. expectType<number | undefined>(compA.c)
  1130. // mixins
  1131. expectType<string>(compA.mA)
  1132. // extends
  1133. expectType<number>(compA.baseA)
  1134. // @ts-expect-error
  1135. compA.a = true
  1136. // @ts-expect-error
  1137. compA.b = 'foo'
  1138. // @ts-expect-error
  1139. compA.c = 1
  1140. // @ts-expect-error
  1141. compA.mA = 'foo'
  1142. // @ts-expect-error
  1143. compA.baseA = 1
  1144. })
  1145. describe('async setup', () => {
  1146. type GT = string & { __brand: unknown }
  1147. const Comp = defineComponent({
  1148. async setup() {
  1149. // setup context
  1150. return {
  1151. a: ref(1),
  1152. b: {
  1153. c: ref('hi'),
  1154. },
  1155. d: reactive({
  1156. e: ref('hello' as GT),
  1157. }),
  1158. }
  1159. },
  1160. render() {
  1161. // assert setup context unwrapping
  1162. expectType<number>(this.a)
  1163. expectType<string>(this.b.c.value)
  1164. expectType<GT>(this.d.e)
  1165. // setup context properties should be mutable
  1166. this.a = 2
  1167. },
  1168. })
  1169. const vm = {} as InstanceType<typeof Comp>
  1170. // assert setup context unwrapping
  1171. expectType<number>(vm.a)
  1172. expectType<string>(vm.b.c.value)
  1173. expectType<GT>(vm.d.e)
  1174. // setup context properties should be mutable
  1175. vm.a = 2
  1176. })
  1177. // #5948
  1178. describe('DefineComponent should infer correct types when assigning to Component', () => {
  1179. let component: Component
  1180. component = defineComponent({
  1181. setup(_, { attrs, slots }) {
  1182. // @ts-expect-error should not be any
  1183. expectType<[]>(attrs)
  1184. // @ts-expect-error should not be any
  1185. expectType<[]>(slots)
  1186. },
  1187. })
  1188. expectType<Component>(component)
  1189. })
  1190. // #5969
  1191. describe('should allow to assign props', () => {
  1192. const Child = defineComponent({
  1193. props: {
  1194. bar: String,
  1195. },
  1196. })
  1197. const Parent = defineComponent({
  1198. props: {
  1199. ...Child.props,
  1200. foo: String,
  1201. },
  1202. })
  1203. const child = new Child()
  1204. expectType<JSX.Element>(<Parent {...child.$props} />)
  1205. })
  1206. // #6052
  1207. describe('prop starting with `on*` is broken', () => {
  1208. defineComponent({
  1209. props: {
  1210. onX: {
  1211. type: Function as PropType<(a: 1) => void>,
  1212. required: true,
  1213. },
  1214. },
  1215. setup(props) {
  1216. expectType<(a: 1) => void>(props.onX)
  1217. props.onX(1)
  1218. },
  1219. })
  1220. defineComponent({
  1221. props: {
  1222. onX: {
  1223. type: Function as PropType<(a: 1) => void>,
  1224. required: true,
  1225. },
  1226. },
  1227. emits: {
  1228. test: (a: 1) => true,
  1229. },
  1230. setup(props) {
  1231. expectType<(a: 1) => void>(props.onX)
  1232. expectType<undefined | ((a: 1) => any)>(props.onTest)
  1233. },
  1234. })
  1235. })
  1236. describe('function syntax w/ generics', () => {
  1237. const Comp = defineComponent(
  1238. // TODO: babel plugin to auto infer runtime props options from type
  1239. // similar to defineProps<{...}>()
  1240. <T extends string | number>(props: { msg: T; list: T[] }) => {
  1241. // use Composition API here like in <script setup>
  1242. const count = ref(0)
  1243. return () => (
  1244. // return a render function (both JSX and h() works)
  1245. <div>
  1246. {props.msg} {count.value}
  1247. </div>
  1248. )
  1249. },
  1250. )
  1251. expectType<JSX.Element>(<Comp msg="fse" list={['foo']} />)
  1252. expectType<JSX.Element>(<Comp msg={123} list={[123]} />)
  1253. expectType<JSX.Element>(
  1254. // @ts-expect-error missing prop
  1255. <Comp msg={123} />,
  1256. )
  1257. expectType<JSX.Element>(
  1258. // @ts-expect-error generics don't match
  1259. <Comp msg="fse" list={[123]} />,
  1260. )
  1261. expectType<JSX.Element>(
  1262. // @ts-expect-error generics don't match
  1263. <Comp msg={123} list={['123']} />,
  1264. )
  1265. })
  1266. describe('function syntax w/ emits', () => {
  1267. const Foo = defineComponent(
  1268. (props: { msg: string }, ctx) => {
  1269. ctx.emit('foo')
  1270. // @ts-expect-error
  1271. ctx.emit('bar')
  1272. return () => {}
  1273. },
  1274. {
  1275. emits: ['foo'],
  1276. },
  1277. )
  1278. expectType<JSX.Element>(<Foo msg="hi" onFoo={() => {}} />)
  1279. // @ts-expect-error
  1280. expectType<JSX.Element>(<Foo msg="hi" onBar={() => {}} />)
  1281. defineComponent(
  1282. (props: { msg: string }, ctx) => {
  1283. ctx.emit('foo', 'hi')
  1284. // @ts-expect-error
  1285. ctx.emit('foo')
  1286. // @ts-expect-error
  1287. ctx.emit('bar')
  1288. return () => {}
  1289. },
  1290. {
  1291. emits: {
  1292. foo: (a: string) => true,
  1293. },
  1294. },
  1295. )
  1296. })
  1297. describe('function syntax w/ runtime props', () => {
  1298. // with runtime props, the runtime props must match
  1299. // manual type declaration
  1300. const Comp1 = defineComponent(
  1301. (_props: { msg: string }) => {
  1302. return () => {}
  1303. },
  1304. {
  1305. props: ['msg'],
  1306. },
  1307. )
  1308. // @ts-expect-error bar isn't specified in props definition
  1309. defineComponent(
  1310. (_props: { msg: string }) => {
  1311. return () => {}
  1312. },
  1313. {
  1314. props: ['msg', 'bar'],
  1315. },
  1316. )
  1317. defineComponent(
  1318. (_props: { msg: string; bar: string }) => {
  1319. return () => {}
  1320. },
  1321. {
  1322. props: ['msg'],
  1323. },
  1324. )
  1325. expectType<JSX.Element>(<Comp1 msg="1" />)
  1326. // @ts-expect-error msg type is incorrect
  1327. expectType<JSX.Element>(<Comp1 msg={1} />)
  1328. // @ts-expect-error msg is missing
  1329. expectType<JSX.Element>(<Comp1 />)
  1330. // @ts-expect-error bar doesn't exist
  1331. expectType<JSX.Element>(<Comp1 msg="1" bar="2" />)
  1332. const Comp2 = defineComponent(
  1333. <T extends string>(_props: { msg: T }) => {
  1334. return () => {}
  1335. },
  1336. {
  1337. props: ['msg'],
  1338. },
  1339. )
  1340. // @ts-expect-error bar isn't specified in props definition
  1341. defineComponent(
  1342. <T extends string>(_props: { msg: T }) => {
  1343. return () => {}
  1344. },
  1345. {
  1346. props: ['msg', 'bar'],
  1347. },
  1348. )
  1349. defineComponent(
  1350. <T extends string>(_props: { msg: T; bar: T }) => {
  1351. return () => {}
  1352. },
  1353. {
  1354. props: ['msg'],
  1355. },
  1356. )
  1357. expectType<JSX.Element>(<Comp2 msg="1" />)
  1358. expectType<JSX.Element>(<Comp2<string> msg="1" />)
  1359. // @ts-expect-error msg type is incorrect
  1360. expectType<JSX.Element>(<Comp2 msg={1} />)
  1361. // @ts-expect-error msg is missing
  1362. expectType<JSX.Element>(<Comp2 />)
  1363. // @ts-expect-error bar doesn't exist
  1364. expectType<JSX.Element>(<Comp2 msg="1" bar="2" />)
  1365. // Note: generics aren't supported with object runtime props
  1366. const Comp3 = defineComponent(
  1367. <T extends string>(_props: { msg: T }) => {
  1368. return () => {}
  1369. },
  1370. {
  1371. props: {
  1372. msg: String,
  1373. },
  1374. },
  1375. )
  1376. defineComponent(
  1377. // @ts-expect-error bar isn't specified in props definition
  1378. <T extends string>(_props: { msg: T }) => {
  1379. return () => {}
  1380. },
  1381. {
  1382. props: {
  1383. bar: String,
  1384. },
  1385. },
  1386. )
  1387. defineComponent(
  1388. // @ts-expect-error generics aren't supported with object runtime props
  1389. <T extends string>(_props: { msg: T; bar: T }) => {
  1390. return () => {}
  1391. },
  1392. {
  1393. props: {
  1394. msg: String,
  1395. },
  1396. },
  1397. )
  1398. expectType<JSX.Element>(<Comp3 msg="1" />)
  1399. // @ts-expect-error generics aren't supported with object runtime props
  1400. expectType<JSX.Element>(<Comp3<string> msg="1" />)
  1401. // @ts-expect-error msg type is incorrect
  1402. expectType<JSX.Element>(<Comp3 msg={1} />)
  1403. // @ts-expect-error msg is missing
  1404. expectType<JSX.Element>(<Comp3 />)
  1405. // @ts-expect-error bar doesn't exist
  1406. expectType<JSX.Element>(<Comp3 msg="1" bar="2" />)
  1407. // @ts-expect-error string prop names don't match
  1408. defineComponent(
  1409. (_props: { msg: string }) => {
  1410. return () => {}
  1411. },
  1412. {
  1413. props: ['bar'],
  1414. },
  1415. )
  1416. defineComponent(
  1417. (_props: { msg: string }) => {
  1418. return () => {}
  1419. },
  1420. {
  1421. props: {
  1422. // @ts-expect-error prop type mismatch
  1423. msg: Number,
  1424. },
  1425. },
  1426. )
  1427. })
  1428. // check if defineComponent can be exported
  1429. export default {
  1430. // function components
  1431. a: defineComponent(_ => () => h('div')),
  1432. // no props
  1433. b: defineComponent({
  1434. data() {
  1435. return {}
  1436. },
  1437. }),
  1438. c: defineComponent({
  1439. props: ['a'],
  1440. }),
  1441. d: defineComponent({
  1442. props: {
  1443. a: Number,
  1444. },
  1445. }),
  1446. }
  1447. describe('slots', () => {
  1448. const comp1 = defineComponent({
  1449. slots: Object as SlotsType<{
  1450. default: { foo: string; bar: number }
  1451. optional?: { data: string }
  1452. undefinedScope: undefined | { data: string }
  1453. optionalUndefinedScope?: undefined | { data: string }
  1454. }>,
  1455. setup(props, { slots }) {
  1456. expectType<(scope: { foo: string; bar: number }) => VNode[]>(
  1457. slots.default,
  1458. )
  1459. expectType<((scope: { data: string }) => VNode[]) | undefined>(
  1460. slots.optional,
  1461. )
  1462. slots.default({ foo: 'foo', bar: 1 })
  1463. // @ts-expect-error it's optional
  1464. slots.optional({ data: 'foo' })
  1465. slots.optional?.({ data: 'foo' })
  1466. expectType<{
  1467. (): VNode[]
  1468. (scope: undefined | { data: string }): VNode[]
  1469. }>(slots.undefinedScope)
  1470. expectType<
  1471. | { (): VNode[]; (scope: undefined | { data: string }): VNode[] }
  1472. | undefined
  1473. >(slots.optionalUndefinedScope)
  1474. slots.default({ foo: 'foo', bar: 1 })
  1475. // @ts-expect-error it's optional
  1476. slots.optional({ data: 'foo' })
  1477. slots.optional?.({ data: 'foo' })
  1478. slots.undefinedScope()
  1479. slots.undefinedScope(undefined)
  1480. // @ts-expect-error
  1481. slots.undefinedScope('foo')
  1482. slots.optionalUndefinedScope?.()
  1483. slots.optionalUndefinedScope?.(undefined)
  1484. slots.optionalUndefinedScope?.({ data: 'foo' })
  1485. // @ts-expect-error
  1486. slots.optionalUndefinedScope()
  1487. // @ts-expect-error
  1488. slots.optionalUndefinedScope?.('foo')
  1489. expectType<typeof slots | undefined>(new comp1().$slots)
  1490. },
  1491. })
  1492. const comp2 = defineComponent({
  1493. setup(props, { slots }) {
  1494. // unknown slots
  1495. expectType<Slots>(slots)
  1496. expectType<((...args: any[]) => VNode[]) | undefined>(slots.default)
  1497. },
  1498. })
  1499. expectType<Slots | undefined>(new comp2().$slots)
  1500. })
  1501. // #5885
  1502. describe('should work when props type is incompatible with setup returned type ', () => {
  1503. type SizeType = 'small' | 'big'
  1504. const Comp = defineComponent({
  1505. props: {
  1506. size: {
  1507. type: String as PropType<SizeType>,
  1508. required: true,
  1509. },
  1510. },
  1511. setup(props) {
  1512. expectType<SizeType>(props.size)
  1513. return {
  1514. size: 1,
  1515. }
  1516. },
  1517. })
  1518. type CompInstance = InstanceType<typeof Comp>
  1519. const CompA = {} as CompInstance
  1520. expectType<ComponentPublicInstance>(CompA)
  1521. expectType<number>(CompA.size)
  1522. expectType<SizeType>(CompA.$props.size)
  1523. })
  1524. describe('withKeys and withModifiers as pro', () => {
  1525. const onKeydown = withKeys(e => {}, [''])
  1526. const onClick = withModifiers(e => {}, [])
  1527. ;<input onKeydown={onKeydown} onClick={onClick} />
  1528. })
  1529. // #3367 expose components types
  1530. describe('expose component types', () => {
  1531. const child = defineComponent({
  1532. props: {
  1533. a: String,
  1534. },
  1535. })
  1536. const parent = defineComponent({
  1537. components: {
  1538. child,
  1539. child2: {
  1540. template: `<div></div>`,
  1541. },
  1542. },
  1543. })
  1544. expectType<typeof child>(parent.components!.child)
  1545. expectType<Component>(parent.components!.child2)
  1546. // global components
  1547. expectType<Readonly<KeepAliveProps>>(
  1548. new parent.components!.KeepAlive().$props,
  1549. )
  1550. expectType<Readonly<KeepAliveProps>>(new child.components!.KeepAlive().$props)
  1551. // runtime-dom components
  1552. expectType<Readonly<TransitionProps>>(
  1553. new parent.components!.Transition().$props,
  1554. )
  1555. expectType<Readonly<TransitionProps>>(
  1556. new child.components!.Transition().$props,
  1557. )
  1558. })
  1559. describe('directive typing', () => {
  1560. const customDirective: Directive = {
  1561. created(_) {},
  1562. }
  1563. const comp = defineComponent({
  1564. props: {
  1565. a: String,
  1566. },
  1567. directives: {
  1568. customDirective,
  1569. localDirective: {
  1570. created(_, { arg }) {
  1571. expectType<string | undefined>(arg)
  1572. },
  1573. },
  1574. },
  1575. })
  1576. expectType<typeof customDirective>(comp.directives!.customDirective)
  1577. expectType<Directive>(comp.directives!.localDirective)
  1578. // global directive
  1579. expectType<typeof vShow>(comp.directives!.vShow)
  1580. })
  1581. describe('expose typing', () => {
  1582. const Comp = defineComponent({
  1583. expose: ['a', 'b'],
  1584. props: {
  1585. some: String,
  1586. },
  1587. data() {
  1588. return { a: 1, b: '2', c: 1 }
  1589. },
  1590. })
  1591. expectType<Array<'a' | 'b'>>(Comp.expose!)
  1592. const vm = new Comp()
  1593. // internal should still be exposed
  1594. vm.$props
  1595. expectType<number>(vm.a)
  1596. expectType<string>(vm.b)
  1597. // @ts-expect-error shouldn't be exposed
  1598. vm.c
  1599. })
  1600. import type {
  1601. AllowedComponentProps,
  1602. ComponentCustomProps,
  1603. ComponentInstance,
  1604. ComponentOptionsMixin,
  1605. DefineComponent,
  1606. Directive,
  1607. EmitsOptions,
  1608. ExtractPropTypes,
  1609. KeepAliveProps,
  1610. TransitionProps,
  1611. VNodeProps,
  1612. vShow,
  1613. } from 'vue'
  1614. // code generated by tsc / vue-tsc, make sure this continues to work
  1615. // so we don't accidentally change the args order of DefineComponent
  1616. declare const MyButton: DefineComponent<
  1617. {},
  1618. () => JSX.Element,
  1619. {},
  1620. {},
  1621. {},
  1622. ComponentOptionsMixin,
  1623. ComponentOptionsMixin,
  1624. EmitsOptions,
  1625. string,
  1626. VNodeProps & AllowedComponentProps & ComponentCustomProps,
  1627. Readonly<ExtractPropTypes<{}>>,
  1628. {},
  1629. {}
  1630. >
  1631. ;<MyButton class="x" />
  1632. describe('__typeProps backdoor for union type for conditional props', () => {
  1633. interface CommonProps {
  1634. size?: 'xl' | 'l' | 'm' | 's' | 'xs'
  1635. }
  1636. type ConditionalProps =
  1637. | {
  1638. color?: 'normal' | 'primary' | 'secondary'
  1639. appearance?: 'normal' | 'outline' | 'text'
  1640. }
  1641. | {
  1642. color: 'white'
  1643. appearance: 'outline'
  1644. }
  1645. type Props = CommonProps & ConditionalProps
  1646. const Comp = defineComponent({
  1647. __typeProps: {} as Props,
  1648. })
  1649. // @ts-expect-error
  1650. ;<Comp color="white" />
  1651. // @ts-expect-error
  1652. ;<Comp color="white" appearance="normal" />
  1653. ;<Comp color="white" appearance="outline" />
  1654. const c = new Comp()
  1655. // @ts-expect-error
  1656. c.$props = { color: 'white' }
  1657. // @ts-expect-error
  1658. c.$props = { color: 'white', appearance: 'text' }
  1659. c.$props = { color: 'white', appearance: 'outline' }
  1660. })
  1661. describe('__typeEmits backdoor, 3.3+ object syntax', () => {
  1662. type Emits = {
  1663. change: [id: number]
  1664. update: [value: string]
  1665. }
  1666. const Comp = defineComponent({
  1667. __typeEmits: {} as Emits,
  1668. mounted() {
  1669. this.$props.onChange?.(123)
  1670. // @ts-expect-error
  1671. this.$props.onChange?.('123')
  1672. this.$props.onUpdate?.('foo')
  1673. // @ts-expect-error
  1674. this.$props.onUpdate?.(123)
  1675. // @ts-expect-error
  1676. this.$emit('foo')
  1677. this.$emit('change', 123)
  1678. // @ts-expect-error
  1679. this.$emit('change', '123')
  1680. this.$emit('update', 'test')
  1681. // @ts-expect-error
  1682. this.$emit('update', 123)
  1683. },
  1684. })
  1685. ;<Comp onChange={id => id.toFixed(2)} />
  1686. ;<Comp onUpdate={id => id.toUpperCase()} />
  1687. // @ts-expect-error
  1688. ;<Comp onChange={id => id.slice(1)} />
  1689. // @ts-expect-error
  1690. ;<Comp onUpdate={id => id.toFixed(2)} />
  1691. const c = new Comp()
  1692. // @ts-expect-error
  1693. c.$emit('foo')
  1694. c.$emit('change', 123)
  1695. // @ts-expect-error
  1696. c.$emit('change', '123')
  1697. c.$emit('update', 'test')
  1698. // @ts-expect-error
  1699. c.$emit('update', 123)
  1700. })
  1701. describe('__typeEmits backdoor, call signature syntax', () => {
  1702. type Emits = {
  1703. (e: 'change', id: number): void
  1704. (e: 'update', value: string): void
  1705. }
  1706. const Comp = defineComponent({
  1707. __typeEmits: {} as Emits,
  1708. mounted() {
  1709. this.$props.onChange?.(123)
  1710. // @ts-expect-error
  1711. this.$props.onChange?.('123')
  1712. this.$props.onUpdate?.('foo')
  1713. // @ts-expect-error
  1714. this.$props.onUpdate?.(123)
  1715. // @ts-expect-error
  1716. this.$emit('foo')
  1717. this.$emit('change', 123)
  1718. // @ts-expect-error
  1719. this.$emit('change', '123')
  1720. this.$emit('update', 'test')
  1721. // @ts-expect-error
  1722. this.$emit('update', 123)
  1723. },
  1724. })
  1725. ;<Comp onChange={id => id.toFixed(2)} />
  1726. ;<Comp onUpdate={id => id.toUpperCase()} />
  1727. // @ts-expect-error
  1728. ;<Comp onChange={id => id.slice(1)} />
  1729. // @ts-expect-error
  1730. ;<Comp onUpdate={id => id.toFixed(2)} />
  1731. const c = new Comp()
  1732. // @ts-expect-error
  1733. c.$emit('foo')
  1734. c.$emit('change', 123)
  1735. // @ts-expect-error
  1736. c.$emit('change', '123')
  1737. c.$emit('update', 'test')
  1738. // @ts-expect-error
  1739. c.$emit('update', 123)
  1740. })
  1741. describe('__typeRefs backdoor, object syntax', () => {
  1742. type Refs = {
  1743. foo: number
  1744. }
  1745. const Parent = defineComponent({
  1746. __typeRefs: {} as { child: ComponentInstance<typeof Child> },
  1747. })
  1748. const Child = defineComponent({
  1749. __typeRefs: {} as Refs,
  1750. })
  1751. const c = new Parent()
  1752. const refs = c.$refs
  1753. expectType<ComponentInstance<typeof Child>>(refs.child)
  1754. expectType<number>(refs.child.$refs.foo)
  1755. })
  1756. describe('__typeEl backdoor', () => {
  1757. const Comp = defineComponent({
  1758. __typeEl: {} as HTMLAnchorElement,
  1759. })
  1760. const c = new Comp()
  1761. expectType<HTMLAnchorElement>(c.$el)
  1762. })
  1763. defineComponent({
  1764. props: {
  1765. foo: [String, null],
  1766. },
  1767. setup(props) {
  1768. expectType<IsAny<typeof props.foo>>(false)
  1769. expectType<string | null | undefined>(props.foo)
  1770. },
  1771. })
  1772. import type * as vue from 'vue'
  1773. interface ErrorMessageSlotProps {
  1774. message: string | undefined
  1775. }
  1776. /**
  1777. * #10842
  1778. * component types generated by vue-tsc
  1779. * relying on legacy CreateComponentPublicInstance signature
  1780. */
  1781. declare const ErrorMessage: {
  1782. new (...args: any[]): vue.CreateComponentPublicInstance<
  1783. Readonly<
  1784. vue.ExtractPropTypes<{
  1785. as: {
  1786. type: StringConstructor
  1787. default: any
  1788. }
  1789. name: {
  1790. type: StringConstructor
  1791. required: true
  1792. }
  1793. }>
  1794. >,
  1795. () =>
  1796. | VNode<
  1797. vue.RendererNode,
  1798. vue.RendererElement,
  1799. {
  1800. [key: string]: any
  1801. }
  1802. >
  1803. | vue.Slot<any>
  1804. | VNode<
  1805. vue.RendererNode,
  1806. vue.RendererElement,
  1807. {
  1808. [key: string]: any
  1809. }
  1810. >[]
  1811. | {
  1812. default: () => VNode<
  1813. vue.RendererNode,
  1814. vue.RendererElement,
  1815. {
  1816. [key: string]: any
  1817. }
  1818. >[]
  1819. },
  1820. unknown,
  1821. {},
  1822. {},
  1823. vue.ComponentOptionsMixin,
  1824. vue.ComponentOptionsMixin,
  1825. {},
  1826. vue.VNodeProps &
  1827. vue.AllowedComponentProps &
  1828. vue.ComponentCustomProps &
  1829. Readonly<
  1830. vue.ExtractPropTypes<{
  1831. as: {
  1832. type: StringConstructor
  1833. default: any
  1834. }
  1835. name: {
  1836. type: StringConstructor
  1837. required: true
  1838. }
  1839. }>
  1840. >,
  1841. {
  1842. as: string
  1843. },
  1844. true,
  1845. {},
  1846. {},
  1847. {
  1848. P: {}
  1849. B: {}
  1850. D: {}
  1851. C: {}
  1852. M: {}
  1853. Defaults: {}
  1854. },
  1855. Readonly<
  1856. vue.ExtractPropTypes<{
  1857. as: {
  1858. type: StringConstructor
  1859. default: any
  1860. }
  1861. name: {
  1862. type: StringConstructor
  1863. required: true
  1864. }
  1865. }>
  1866. >,
  1867. () =>
  1868. | VNode<
  1869. vue.RendererNode,
  1870. vue.RendererElement,
  1871. {
  1872. [key: string]: any
  1873. }
  1874. >
  1875. | vue.Slot<any>
  1876. | VNode<
  1877. vue.RendererNode,
  1878. vue.RendererElement,
  1879. {
  1880. [key: string]: any
  1881. }
  1882. >[]
  1883. | {
  1884. default: () => VNode<
  1885. vue.RendererNode,
  1886. vue.RendererElement,
  1887. {
  1888. [key: string]: any
  1889. }
  1890. >[]
  1891. },
  1892. {},
  1893. {},
  1894. {},
  1895. {
  1896. as: string
  1897. }
  1898. >
  1899. __isFragment?: never
  1900. __isTeleport?: never
  1901. __isSuspense?: never
  1902. } & vue.ComponentOptionsBase<
  1903. Readonly<
  1904. vue.ExtractPropTypes<{
  1905. as: {
  1906. type: StringConstructor
  1907. default: any
  1908. }
  1909. name: {
  1910. type: StringConstructor
  1911. required: true
  1912. }
  1913. }>
  1914. >,
  1915. () =>
  1916. | VNode<
  1917. vue.RendererNode,
  1918. vue.RendererElement,
  1919. {
  1920. [key: string]: any
  1921. }
  1922. >
  1923. | vue.Slot<any>
  1924. | VNode<
  1925. vue.RendererNode,
  1926. vue.RendererElement,
  1927. {
  1928. [key: string]: any
  1929. }
  1930. >[]
  1931. | {
  1932. default: () => VNode<
  1933. vue.RendererNode,
  1934. vue.RendererElement,
  1935. {
  1936. [key: string]: any
  1937. }
  1938. >[]
  1939. },
  1940. unknown,
  1941. {},
  1942. {},
  1943. vue.ComponentOptionsMixin,
  1944. vue.ComponentOptionsMixin,
  1945. {},
  1946. string,
  1947. {
  1948. as: string
  1949. },
  1950. {},
  1951. string,
  1952. {}
  1953. > &
  1954. vue.VNodeProps &
  1955. vue.AllowedComponentProps &
  1956. vue.ComponentCustomProps &
  1957. (new () => {
  1958. $slots: {
  1959. default: (arg: ErrorMessageSlotProps) => VNode[]
  1960. }
  1961. })
  1962. ;<ErrorMessage name="password" class="error" />
  1963. // #10843
  1964. createApp({}).component(
  1965. 'SomeComponent',
  1966. defineComponent({
  1967. props: {
  1968. title: String,
  1969. },
  1970. setup(props) {
  1971. expectType<string | undefined>(props.title)
  1972. return {}
  1973. },
  1974. }),
  1975. )
  1976. const Comp = defineComponent({
  1977. props: {
  1978. actionText: {
  1979. type: {} as PropType<string>,
  1980. default: 'Become a sponsor',
  1981. },
  1982. },
  1983. __typeProps: {} as {
  1984. actionText?: string
  1985. },
  1986. })
  1987. const instance = new Comp()
  1988. function expectString(s: string) {}
  1989. // instance prop with default should be non-null
  1990. expectString(instance.actionText)
  1991. // public prop on $props should be optional
  1992. // @ts-expect-error
  1993. expectString(instance.$props.actionText)
  1994. // #12122
  1995. defineComponent({
  1996. props: { foo: String },
  1997. render() {
  1998. expectType<{ readonly foo?: string }>(this.$props)
  1999. // @ts-expect-error
  2000. expectType<string>(this.$props)
  2001. },
  2002. })
  2003. // #14117
  2004. defineComponent({
  2005. setup() {
  2006. const setup1 = ref('setup1')
  2007. const setup2 = ref('setup2')
  2008. return { setup1, setup2 }
  2009. },
  2010. data() {
  2011. return {
  2012. data1: 1,
  2013. }
  2014. },
  2015. props: {
  2016. props1: {
  2017. type: String,
  2018. },
  2019. },
  2020. methods: {
  2021. methods1() {
  2022. return `methods1`
  2023. },
  2024. },
  2025. computed: {
  2026. computed1() {
  2027. this.setup1
  2028. this.setup2
  2029. this.data1
  2030. this.props1
  2031. this.methods1()
  2032. return `computed1`
  2033. },
  2034. },
  2035. expose: ['setup1'],
  2036. })