defineComponent.test-d.tsx 46 KB

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