2
0

defineComponent.test-d.tsx 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029
  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. Focus: (f: boolean) => !!f,
  843. },
  844. setup(props, { emit }) {
  845. expectType<((n: number) => boolean) | undefined>(props.onClick)
  846. expectType<((b: string) => boolean) | undefined>(props.onInput)
  847. expectType<((f: boolean) => boolean) | undefined>(props.onFocus)
  848. emit('click', 1)
  849. emit('input', 'foo')
  850. emit('Focus', true)
  851. // @ts-expect-error
  852. emit('nope')
  853. // @ts-expect-error
  854. emit('click')
  855. // @ts-expect-error
  856. emit('click', 'foo')
  857. // @ts-expect-error
  858. emit('input')
  859. // @ts-expect-error
  860. emit('input', 1)
  861. // @ts-expect-error
  862. emit('focus')
  863. // @ts-expect-error
  864. emit('focus', true)
  865. },
  866. created() {
  867. this.$emit('click', 1)
  868. this.$emit('input', 'foo')
  869. // @ts-expect-error
  870. this.$emit('nope')
  871. // @ts-expect-error
  872. this.$emit('click')
  873. // @ts-expect-error
  874. this.$emit('click', 'foo')
  875. // @ts-expect-error
  876. this.$emit('input')
  877. // @ts-expect-error
  878. this.$emit('input', 1)
  879. // @ts-expect-error
  880. this.$emit('focus')
  881. // @ts-expect-error
  882. this.$emit('focus', true)
  883. },
  884. mounted() {
  885. // #3599
  886. this.$nextTick(function () {
  887. // this should be bound to this instance
  888. this.$emit('click', 1)
  889. this.$emit('input', 'foo')
  890. // @ts-expect-error
  891. this.$emit('nope')
  892. // @ts-expect-error
  893. this.$emit('click')
  894. // @ts-expect-error
  895. this.$emit('click', 'foo')
  896. // @ts-expect-error
  897. this.$emit('input')
  898. // @ts-expect-error
  899. this.$emit('input', 1)
  900. // @ts-expect-error
  901. this.$emit('focus')
  902. // @ts-expect-error
  903. this.$emit('focus', true)
  904. })
  905. },
  906. })
  907. // with array emits
  908. defineComponent({
  909. emits: ['foo', 'bar'],
  910. setup(props, { emit }) {
  911. expectType<((...args: any[]) => any) | undefined>(props.onFoo)
  912. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  913. emit('foo')
  914. emit('foo', 123)
  915. emit('bar')
  916. // @ts-expect-error
  917. emit('nope')
  918. },
  919. created() {
  920. this.$emit('foo')
  921. this.$emit('foo', 123)
  922. this.$emit('bar')
  923. // @ts-expect-error
  924. this.$emit('nope')
  925. },
  926. })
  927. // with tsx
  928. const Component = defineComponent({
  929. emits: {
  930. click: (n: number) => typeof n === 'number',
  931. },
  932. setup(props, { emit }) {
  933. expectType<((n: number) => any) | undefined>(props.onClick)
  934. emit('click', 1)
  935. // @ts-expect-error
  936. emit('click')
  937. // @ts-expect-error
  938. emit('click', 'foo')
  939. },
  940. })
  941. defineComponent({
  942. render() {
  943. return (
  944. <Component
  945. onClick={(n: number) => {
  946. return n + 1
  947. }}
  948. />
  949. )
  950. },
  951. })
  952. // without emits
  953. defineComponent({
  954. setup(props, { emit }) {
  955. emit('test', 1)
  956. emit('test')
  957. },
  958. })
  959. // emit should be valid when ComponentPublicInstance is used.
  960. const instance = {} as ComponentPublicInstance
  961. instance.$emit('test', 1)
  962. instance.$emit('test')
  963. // `this` should be void inside of emits validators
  964. defineComponent({
  965. props: ['bar'],
  966. emits: {
  967. foo(): boolean {
  968. // @ts-expect-error
  969. return this.bar === 3
  970. },
  971. },
  972. })
  973. })
  974. describe('inject', () => {
  975. // with object inject
  976. defineComponent({
  977. props: {
  978. a: String,
  979. },
  980. inject: {
  981. foo: 'foo',
  982. bar: 'bar',
  983. },
  984. created() {
  985. expectType<unknown>(this.foo)
  986. expectType<unknown>(this.bar)
  987. // @ts-expect-error
  988. this.foobar = 1
  989. },
  990. })
  991. // with array inject
  992. defineComponent({
  993. props: ['a', 'b'],
  994. inject: ['foo', 'bar'],
  995. created() {
  996. expectType<unknown>(this.foo)
  997. expectType<unknown>(this.bar)
  998. // @ts-expect-error
  999. this.foobar = 1
  1000. },
  1001. })
  1002. // with no props
  1003. defineComponent({
  1004. inject: {
  1005. foo: {
  1006. from: 'pfoo',
  1007. default: 'foo',
  1008. },
  1009. bar: {
  1010. from: 'pbar',
  1011. default: 'bar',
  1012. },
  1013. },
  1014. created() {
  1015. expectType<unknown>(this.foo)
  1016. expectType<unknown>(this.bar)
  1017. // @ts-expect-error
  1018. this.foobar = 1
  1019. },
  1020. })
  1021. // without inject
  1022. defineComponent({
  1023. props: ['a', 'b'],
  1024. created() {
  1025. // @ts-expect-error
  1026. this.foo = 1
  1027. // @ts-expect-error
  1028. this.bar = 1
  1029. },
  1030. })
  1031. })
  1032. describe('componentOptions setup should be `SetupContext`', () => {
  1033. expectType<ComponentOptions['setup']>(
  1034. {} as (props: Record<string, any>, ctx: SetupContext) => any,
  1035. )
  1036. })
  1037. describe('extract instance type', () => {
  1038. const Base = defineComponent({
  1039. props: {
  1040. baseA: {
  1041. type: Number,
  1042. default: 1,
  1043. },
  1044. },
  1045. })
  1046. const MixinA = defineComponent({
  1047. props: {
  1048. mA: {
  1049. type: String,
  1050. default: '',
  1051. },
  1052. },
  1053. })
  1054. const CompA = defineComponent({
  1055. extends: Base,
  1056. mixins: [MixinA],
  1057. props: {
  1058. a: {
  1059. type: Boolean,
  1060. default: false,
  1061. },
  1062. b: {
  1063. type: String,
  1064. required: true,
  1065. },
  1066. c: Number,
  1067. },
  1068. })
  1069. const compA = {} as InstanceType<typeof CompA>
  1070. expectType<boolean>(compA.a)
  1071. expectType<string>(compA.b)
  1072. expectType<number | undefined>(compA.c)
  1073. // mixins
  1074. expectType<string>(compA.mA)
  1075. // extends
  1076. expectType<number>(compA.baseA)
  1077. // @ts-expect-error
  1078. compA.a = true
  1079. // @ts-expect-error
  1080. compA.b = 'foo'
  1081. // @ts-expect-error
  1082. compA.c = 1
  1083. // @ts-expect-error
  1084. compA.mA = 'foo'
  1085. // @ts-expect-error
  1086. compA.baseA = 1
  1087. })
  1088. describe('async setup', () => {
  1089. type GT = string & { __brand: unknown }
  1090. const Comp = defineComponent({
  1091. async setup() {
  1092. // setup context
  1093. return {
  1094. a: ref(1),
  1095. b: {
  1096. c: ref('hi'),
  1097. },
  1098. d: reactive({
  1099. e: ref('hello' as GT),
  1100. }),
  1101. }
  1102. },
  1103. render() {
  1104. // assert setup context unwrapping
  1105. expectType<number>(this.a)
  1106. expectType<string>(this.b.c.value)
  1107. expectType<GT>(this.d.e)
  1108. // setup context properties should be mutable
  1109. this.a = 2
  1110. },
  1111. })
  1112. const vm = {} as InstanceType<typeof Comp>
  1113. // assert setup context unwrapping
  1114. expectType<number>(vm.a)
  1115. expectType<string>(vm.b.c.value)
  1116. expectType<GT>(vm.d.e)
  1117. // setup context properties should be mutable
  1118. vm.a = 2
  1119. })
  1120. // #5948
  1121. describe('DefineComponent should infer correct types when assigning to Component', () => {
  1122. let component: Component
  1123. component = defineComponent({
  1124. setup(_, { attrs, slots }) {
  1125. // @ts-expect-error should not be any
  1126. expectType<[]>(attrs)
  1127. // @ts-expect-error should not be any
  1128. expectType<[]>(slots)
  1129. },
  1130. })
  1131. expectType<Component>(component)
  1132. })
  1133. // #5969
  1134. describe('should allow to assign props', () => {
  1135. const Child = defineComponent({
  1136. props: {
  1137. bar: String,
  1138. },
  1139. })
  1140. const Parent = defineComponent({
  1141. props: {
  1142. ...Child.props,
  1143. foo: String,
  1144. },
  1145. })
  1146. const child = new Child()
  1147. expectType<JSX.Element>(<Parent {...child.$props} />)
  1148. })
  1149. // #6052
  1150. describe('prop starting with `on*` is broken', () => {
  1151. defineComponent({
  1152. props: {
  1153. onX: {
  1154. type: Function as PropType<(a: 1) => void>,
  1155. required: true,
  1156. },
  1157. },
  1158. setup(props) {
  1159. expectType<(a: 1) => void>(props.onX)
  1160. props.onX(1)
  1161. },
  1162. })
  1163. defineComponent({
  1164. props: {
  1165. onX: {
  1166. type: Function as PropType<(a: 1) => void>,
  1167. required: true,
  1168. },
  1169. },
  1170. emits: {
  1171. test: (a: 1) => true,
  1172. },
  1173. setup(props) {
  1174. expectType<(a: 1) => void>(props.onX)
  1175. expectType<undefined | ((a: 1) => any)>(props.onTest)
  1176. },
  1177. })
  1178. })
  1179. describe('function syntax w/ generics', () => {
  1180. const Comp = defineComponent(
  1181. // TODO: babel plugin to auto infer runtime props options from type
  1182. // similar to defineProps<{...}>()
  1183. <T extends string | number>(props: { msg: T; list: T[] }) => {
  1184. // use Composition API here like in <script setup>
  1185. const count = ref(0)
  1186. return () => (
  1187. // return a render function (both JSX and h() works)
  1188. <div>
  1189. {props.msg} {count.value}
  1190. </div>
  1191. )
  1192. },
  1193. )
  1194. expectType<JSX.Element>(<Comp msg="fse" list={['foo']} />)
  1195. expectType<JSX.Element>(<Comp msg={123} list={[123]} />)
  1196. expectType<JSX.Element>(
  1197. // @ts-expect-error missing prop
  1198. <Comp msg={123} />,
  1199. )
  1200. expectType<JSX.Element>(
  1201. // @ts-expect-error generics don't match
  1202. <Comp msg="fse" list={[123]} />,
  1203. )
  1204. expectType<JSX.Element>(
  1205. // @ts-expect-error generics don't match
  1206. <Comp msg={123} list={['123']} />,
  1207. )
  1208. })
  1209. describe('function syntax w/ emits', () => {
  1210. const Foo = defineComponent(
  1211. (props: { msg: string }, ctx) => {
  1212. ctx.emit('foo')
  1213. // @ts-expect-error
  1214. ctx.emit('bar')
  1215. return () => {}
  1216. },
  1217. {
  1218. emits: ['foo'],
  1219. },
  1220. )
  1221. expectType<JSX.Element>(<Foo msg="hi" onFoo={() => {}} />)
  1222. // @ts-expect-error
  1223. expectType<JSX.Element>(<Foo msg="hi" onBar={() => {}} />)
  1224. defineComponent(
  1225. (props: { msg: string }, ctx) => {
  1226. ctx.emit('foo', 'hi')
  1227. // @ts-expect-error
  1228. ctx.emit('foo')
  1229. // @ts-expect-error
  1230. ctx.emit('bar')
  1231. return () => {}
  1232. },
  1233. {
  1234. emits: {
  1235. foo: (a: string) => true,
  1236. },
  1237. },
  1238. )
  1239. })
  1240. describe('function syntax w/ runtime props', () => {
  1241. // with runtime props, the runtime props must match
  1242. // manual type declaration
  1243. defineComponent(
  1244. (_props: { msg: string }) => {
  1245. return () => {}
  1246. },
  1247. {
  1248. props: ['msg'],
  1249. },
  1250. )
  1251. defineComponent(
  1252. <T extends string>(_props: { msg: T }) => {
  1253. return () => {}
  1254. },
  1255. {
  1256. props: ['msg'],
  1257. },
  1258. )
  1259. defineComponent(
  1260. <T extends string>(_props: { msg: T }) => {
  1261. return () => {}
  1262. },
  1263. {
  1264. props: {
  1265. msg: String,
  1266. },
  1267. },
  1268. )
  1269. // @ts-expect-error string prop names don't match
  1270. defineComponent(
  1271. (_props: { msg: string }) => {
  1272. return () => {}
  1273. },
  1274. {
  1275. props: ['bar'],
  1276. },
  1277. )
  1278. defineComponent(
  1279. (_props: { msg: string }) => {
  1280. return () => {}
  1281. },
  1282. {
  1283. props: {
  1284. // @ts-expect-error prop type mismatch
  1285. msg: Number,
  1286. },
  1287. },
  1288. )
  1289. // @ts-expect-error prop keys don't match
  1290. defineComponent(
  1291. (_props: { msg: string }, ctx) => {
  1292. return () => {}
  1293. },
  1294. {
  1295. props: {
  1296. msg: String,
  1297. bar: String,
  1298. },
  1299. },
  1300. )
  1301. })
  1302. // check if defineComponent can be exported
  1303. export default {
  1304. // function components
  1305. a: defineComponent(_ => () => h('div')),
  1306. // no props
  1307. b: defineComponent({
  1308. data() {
  1309. return {}
  1310. },
  1311. }),
  1312. c: defineComponent({
  1313. props: ['a'],
  1314. }),
  1315. d: defineComponent({
  1316. props: {
  1317. a: Number,
  1318. },
  1319. }),
  1320. }
  1321. describe('slots', () => {
  1322. const comp1 = defineComponent({
  1323. slots: Object as SlotsType<{
  1324. default: { foo: string; bar: number }
  1325. optional?: { data: string }
  1326. undefinedScope: undefined | { data: string }
  1327. optionalUndefinedScope?: undefined | { data: string }
  1328. }>,
  1329. setup(props, { slots }) {
  1330. expectType<(scope: { foo: string; bar: number }) => VNode[]>(
  1331. slots.default,
  1332. )
  1333. expectType<((scope: { data: string }) => VNode[]) | undefined>(
  1334. slots.optional,
  1335. )
  1336. slots.default({ foo: 'foo', bar: 1 })
  1337. // @ts-expect-error it's optional
  1338. slots.optional({ data: 'foo' })
  1339. slots.optional?.({ data: 'foo' })
  1340. expectType<{
  1341. (): VNode[]
  1342. (scope: undefined | { data: string }): VNode[]
  1343. }>(slots.undefinedScope)
  1344. expectType<
  1345. | { (): VNode[]; (scope: undefined | { data: string }): VNode[] }
  1346. | undefined
  1347. >(slots.optionalUndefinedScope)
  1348. slots.default({ foo: 'foo', bar: 1 })
  1349. // @ts-expect-error it's optional
  1350. slots.optional({ data: 'foo' })
  1351. slots.optional?.({ data: 'foo' })
  1352. slots.undefinedScope()
  1353. slots.undefinedScope(undefined)
  1354. // @ts-expect-error
  1355. slots.undefinedScope('foo')
  1356. slots.optionalUndefinedScope?.()
  1357. slots.optionalUndefinedScope?.(undefined)
  1358. slots.optionalUndefinedScope?.({ data: 'foo' })
  1359. // @ts-expect-error
  1360. slots.optionalUndefinedScope()
  1361. // @ts-expect-error
  1362. slots.optionalUndefinedScope?.('foo')
  1363. expectType<typeof slots | undefined>(new comp1().$slots)
  1364. },
  1365. })
  1366. const comp2 = defineComponent({
  1367. setup(props, { slots }) {
  1368. // unknown slots
  1369. expectType<Slots>(slots)
  1370. expectType<((...args: any[]) => VNode[]) | undefined>(slots.default)
  1371. },
  1372. })
  1373. expectType<Slots | undefined>(new comp2().$slots)
  1374. })
  1375. // #5885
  1376. describe('should work when props type is incompatible with setup returned type ', () => {
  1377. type SizeType = 'small' | 'big'
  1378. const Comp = defineComponent({
  1379. props: {
  1380. size: {
  1381. type: String as PropType<SizeType>,
  1382. required: true,
  1383. },
  1384. },
  1385. setup(props) {
  1386. expectType<SizeType>(props.size)
  1387. return {
  1388. size: 1,
  1389. }
  1390. },
  1391. })
  1392. type CompInstance = InstanceType<typeof Comp>
  1393. const CompA = {} as CompInstance
  1394. expectType<ComponentPublicInstance>(CompA)
  1395. expectType<number>(CompA.size)
  1396. expectType<SizeType>(CompA.$props.size)
  1397. })
  1398. describe('withKeys and withModifiers as pro', () => {
  1399. const onKeydown = withKeys(e => {}, [''])
  1400. const onClick = withModifiers(e => {}, [])
  1401. ;<input onKeydown={onKeydown} onClick={onClick} />
  1402. })
  1403. // #3367 expose components types
  1404. describe('expose component types', () => {
  1405. const child = defineComponent({
  1406. props: {
  1407. a: String,
  1408. },
  1409. })
  1410. const parent = defineComponent({
  1411. components: {
  1412. child,
  1413. child2: {
  1414. template: `<div></div>`,
  1415. },
  1416. },
  1417. })
  1418. expectType<typeof child>(parent.components!.child)
  1419. expectType<Component>(parent.components!.child2)
  1420. // global components
  1421. expectType<Readonly<KeepAliveProps>>(
  1422. new parent.components!.KeepAlive().$props,
  1423. )
  1424. expectType<Readonly<KeepAliveProps>>(new child.components!.KeepAlive().$props)
  1425. // runtime-dom components
  1426. expectType<Readonly<TransitionProps>>(
  1427. new parent.components!.Transition().$props,
  1428. )
  1429. expectType<Readonly<TransitionProps>>(
  1430. new child.components!.Transition().$props,
  1431. )
  1432. })
  1433. describe('directive typing', () => {
  1434. const customDirective: Directive = {
  1435. created(_) {},
  1436. }
  1437. const comp = defineComponent({
  1438. props: {
  1439. a: String,
  1440. },
  1441. directives: {
  1442. customDirective,
  1443. localDirective: {
  1444. created(_, { arg }) {
  1445. expectType<string | undefined>(arg)
  1446. },
  1447. },
  1448. },
  1449. })
  1450. expectType<typeof customDirective>(comp.directives!.customDirective)
  1451. expectType<Directive>(comp.directives!.localDirective)
  1452. // global directive
  1453. expectType<typeof vShow>(comp.directives!.vShow)
  1454. })
  1455. describe('expose typing', () => {
  1456. const Comp = defineComponent({
  1457. expose: ['a', 'b'],
  1458. props: {
  1459. some: String,
  1460. },
  1461. data() {
  1462. return { a: 1, b: '2', c: 1 }
  1463. },
  1464. })
  1465. expectType<Array<'a' | 'b'>>(Comp.expose!)
  1466. const vm = new Comp()
  1467. // internal should still be exposed
  1468. vm.$props
  1469. expectType<number>(vm.a)
  1470. expectType<string>(vm.b)
  1471. // @ts-expect-error shouldn't be exposed
  1472. vm.c
  1473. })
  1474. import type {
  1475. AllowedComponentProps,
  1476. ComponentCustomProps,
  1477. ComponentInstance,
  1478. ComponentOptionsMixin,
  1479. DefineComponent,
  1480. Directive,
  1481. EmitsOptions,
  1482. ExtractPropTypes,
  1483. KeepAliveProps,
  1484. TransitionProps,
  1485. VNodeProps,
  1486. vShow,
  1487. } from 'vue'
  1488. // code generated by tsc / vue-tsc, make sure this continues to work
  1489. // so we don't accidentally change the args order of DefineComponent
  1490. declare const MyButton: DefineComponent<
  1491. {},
  1492. () => JSX.Element,
  1493. {},
  1494. {},
  1495. {},
  1496. ComponentOptionsMixin,
  1497. ComponentOptionsMixin,
  1498. EmitsOptions,
  1499. string,
  1500. VNodeProps & AllowedComponentProps & ComponentCustomProps,
  1501. Readonly<ExtractPropTypes<{}>>,
  1502. {},
  1503. {}
  1504. >
  1505. ;<MyButton class="x" />
  1506. describe('__typeProps backdoor for union type for conditional props', () => {
  1507. interface CommonProps {
  1508. size?: 'xl' | 'l' | 'm' | 's' | 'xs'
  1509. }
  1510. type ConditionalProps =
  1511. | {
  1512. color?: 'normal' | 'primary' | 'secondary'
  1513. appearance?: 'normal' | 'outline' | 'text'
  1514. }
  1515. | {
  1516. color: 'white'
  1517. appearance: 'outline'
  1518. }
  1519. type Props = CommonProps & ConditionalProps
  1520. const Comp = defineComponent({
  1521. __typeProps: {} as Props,
  1522. })
  1523. // @ts-expect-error
  1524. ;<Comp color="white" />
  1525. // @ts-expect-error
  1526. ;<Comp color="white" appearance="normal" />
  1527. ;<Comp color="white" appearance="outline" />
  1528. const c = new Comp()
  1529. // @ts-expect-error
  1530. c.$props = { color: 'white' }
  1531. // @ts-expect-error
  1532. c.$props = { color: 'white', appearance: 'text' }
  1533. c.$props = { color: 'white', appearance: 'outline' }
  1534. })
  1535. describe('__typeEmits backdoor, 3.3+ object syntax', () => {
  1536. type Emits = {
  1537. change: [id: number]
  1538. update: [value: string]
  1539. }
  1540. const Comp = defineComponent({
  1541. __typeEmits: {} as Emits,
  1542. mounted() {
  1543. this.$props.onChange?.(123)
  1544. // @ts-expect-error
  1545. this.$props.onChange?.('123')
  1546. this.$props.onUpdate?.('foo')
  1547. // @ts-expect-error
  1548. this.$props.onUpdate?.(123)
  1549. // @ts-expect-error
  1550. this.$emit('foo')
  1551. this.$emit('change', 123)
  1552. // @ts-expect-error
  1553. this.$emit('change', '123')
  1554. this.$emit('update', 'test')
  1555. // @ts-expect-error
  1556. this.$emit('update', 123)
  1557. },
  1558. })
  1559. ;<Comp onChange={id => id.toFixed(2)} />
  1560. ;<Comp onUpdate={id => id.toUpperCase()} />
  1561. // @ts-expect-error
  1562. ;<Comp onChange={id => id.slice(1)} />
  1563. // @ts-expect-error
  1564. ;<Comp onUpdate={id => id.toFixed(2)} />
  1565. const c = new Comp()
  1566. // @ts-expect-error
  1567. c.$emit('foo')
  1568. c.$emit('change', 123)
  1569. // @ts-expect-error
  1570. c.$emit('change', '123')
  1571. c.$emit('update', 'test')
  1572. // @ts-expect-error
  1573. c.$emit('update', 123)
  1574. })
  1575. describe('__typeEmits backdoor, call signature syntax', () => {
  1576. type Emits = {
  1577. (e: 'change', id: number): void
  1578. (e: 'update', value: string): void
  1579. }
  1580. const Comp = defineComponent({
  1581. __typeEmits: {} as Emits,
  1582. mounted() {
  1583. this.$props.onChange?.(123)
  1584. // @ts-expect-error
  1585. this.$props.onChange?.('123')
  1586. this.$props.onUpdate?.('foo')
  1587. // @ts-expect-error
  1588. this.$props.onUpdate?.(123)
  1589. // @ts-expect-error
  1590. this.$emit('foo')
  1591. this.$emit('change', 123)
  1592. // @ts-expect-error
  1593. this.$emit('change', '123')
  1594. this.$emit('update', 'test')
  1595. // @ts-expect-error
  1596. this.$emit('update', 123)
  1597. },
  1598. })
  1599. ;<Comp onChange={id => id.toFixed(2)} />
  1600. ;<Comp onUpdate={id => id.toUpperCase()} />
  1601. // @ts-expect-error
  1602. ;<Comp onChange={id => id.slice(1)} />
  1603. // @ts-expect-error
  1604. ;<Comp onUpdate={id => id.toFixed(2)} />
  1605. const c = new Comp()
  1606. // @ts-expect-error
  1607. c.$emit('foo')
  1608. c.$emit('change', 123)
  1609. // @ts-expect-error
  1610. c.$emit('change', '123')
  1611. c.$emit('update', 'test')
  1612. // @ts-expect-error
  1613. c.$emit('update', 123)
  1614. })
  1615. describe('__typeRefs backdoor, object syntax', () => {
  1616. type Refs = {
  1617. foo: number
  1618. }
  1619. const Parent = defineComponent({
  1620. __typeRefs: {} as { child: ComponentInstance<typeof Child> },
  1621. })
  1622. const Child = defineComponent({
  1623. __typeRefs: {} as Refs,
  1624. })
  1625. const c = new Parent()
  1626. const refs = c.$refs
  1627. expectType<ComponentInstance<typeof Child>>(refs.child)
  1628. expectType<number>(refs.child.$refs.foo)
  1629. })
  1630. defineComponent({
  1631. props: {
  1632. foo: [String, null],
  1633. },
  1634. setup(props) {
  1635. expectType<IsAny<typeof props.foo>>(false)
  1636. expectType<string | null | undefined>(props.foo)
  1637. },
  1638. })
  1639. import type * as vue from 'vue'
  1640. interface ErrorMessageSlotProps {
  1641. message: string | undefined
  1642. }
  1643. /**
  1644. * #10842
  1645. * component types generated by vue-tsc
  1646. * relying on legacy CreateComponentPublicInstance signature
  1647. */
  1648. declare const ErrorMessage: {
  1649. new (...args: any[]): vue.CreateComponentPublicInstance<
  1650. Readonly<
  1651. vue.ExtractPropTypes<{
  1652. as: {
  1653. type: StringConstructor
  1654. default: any
  1655. }
  1656. name: {
  1657. type: StringConstructor
  1658. required: true
  1659. }
  1660. }>
  1661. >,
  1662. () =>
  1663. | VNode<
  1664. vue.RendererNode,
  1665. vue.RendererElement,
  1666. {
  1667. [key: string]: any
  1668. }
  1669. >
  1670. | vue.Slot<any>
  1671. | VNode<
  1672. vue.RendererNode,
  1673. vue.RendererElement,
  1674. {
  1675. [key: string]: any
  1676. }
  1677. >[]
  1678. | {
  1679. default: () => VNode<
  1680. vue.RendererNode,
  1681. vue.RendererElement,
  1682. {
  1683. [key: string]: any
  1684. }
  1685. >[]
  1686. },
  1687. unknown,
  1688. {},
  1689. {},
  1690. vue.ComponentOptionsMixin,
  1691. vue.ComponentOptionsMixin,
  1692. {},
  1693. vue.VNodeProps &
  1694. vue.AllowedComponentProps &
  1695. vue.ComponentCustomProps &
  1696. Readonly<
  1697. vue.ExtractPropTypes<{
  1698. as: {
  1699. type: StringConstructor
  1700. default: any
  1701. }
  1702. name: {
  1703. type: StringConstructor
  1704. required: true
  1705. }
  1706. }>
  1707. >,
  1708. {
  1709. as: string
  1710. },
  1711. true,
  1712. {},
  1713. {},
  1714. {
  1715. P: {}
  1716. B: {}
  1717. D: {}
  1718. C: {}
  1719. M: {}
  1720. Defaults: {}
  1721. },
  1722. Readonly<
  1723. vue.ExtractPropTypes<{
  1724. as: {
  1725. type: StringConstructor
  1726. default: any
  1727. }
  1728. name: {
  1729. type: StringConstructor
  1730. required: true
  1731. }
  1732. }>
  1733. >,
  1734. () =>
  1735. | VNode<
  1736. vue.RendererNode,
  1737. vue.RendererElement,
  1738. {
  1739. [key: string]: any
  1740. }
  1741. >
  1742. | vue.Slot<any>
  1743. | VNode<
  1744. vue.RendererNode,
  1745. vue.RendererElement,
  1746. {
  1747. [key: string]: any
  1748. }
  1749. >[]
  1750. | {
  1751. default: () => VNode<
  1752. vue.RendererNode,
  1753. vue.RendererElement,
  1754. {
  1755. [key: string]: any
  1756. }
  1757. >[]
  1758. },
  1759. {},
  1760. {},
  1761. {},
  1762. {
  1763. as: string
  1764. }
  1765. >
  1766. __isFragment?: never
  1767. __isTeleport?: never
  1768. __isSuspense?: never
  1769. } & vue.ComponentOptionsBase<
  1770. Readonly<
  1771. vue.ExtractPropTypes<{
  1772. as: {
  1773. type: StringConstructor
  1774. default: any
  1775. }
  1776. name: {
  1777. type: StringConstructor
  1778. required: true
  1779. }
  1780. }>
  1781. >,
  1782. () =>
  1783. | VNode<
  1784. vue.RendererNode,
  1785. vue.RendererElement,
  1786. {
  1787. [key: string]: any
  1788. }
  1789. >
  1790. | vue.Slot<any>
  1791. | VNode<
  1792. vue.RendererNode,
  1793. vue.RendererElement,
  1794. {
  1795. [key: string]: any
  1796. }
  1797. >[]
  1798. | {
  1799. default: () => VNode<
  1800. vue.RendererNode,
  1801. vue.RendererElement,
  1802. {
  1803. [key: string]: any
  1804. }
  1805. >[]
  1806. },
  1807. unknown,
  1808. {},
  1809. {},
  1810. vue.ComponentOptionsMixin,
  1811. vue.ComponentOptionsMixin,
  1812. {},
  1813. string,
  1814. {
  1815. as: string
  1816. },
  1817. {},
  1818. string,
  1819. {}
  1820. > &
  1821. vue.VNodeProps &
  1822. vue.AllowedComponentProps &
  1823. vue.ComponentCustomProps &
  1824. (new () => {
  1825. $slots: {
  1826. default: (arg: ErrorMessageSlotProps) => VNode[]
  1827. }
  1828. })
  1829. ;<ErrorMessage name="password" class="error" />
  1830. // #10843
  1831. createApp({}).component(
  1832. 'SomeComponent',
  1833. defineComponent({
  1834. props: {
  1835. title: String,
  1836. },
  1837. setup(props) {
  1838. expectType<string | undefined>(props.title)
  1839. return {}
  1840. },
  1841. }),
  1842. )
  1843. const Comp = defineComponent({
  1844. props: {
  1845. actionText: {
  1846. type: {} as PropType<string>,
  1847. default: 'Become a sponsor',
  1848. },
  1849. },
  1850. __typeProps: {} as {
  1851. actionText?: string
  1852. },
  1853. })
  1854. const instance = new Comp()
  1855. function expectString(s: string) {}
  1856. // instance prop with default should be non-null
  1857. expectString(instance.actionText)
  1858. // public prop on $props should be optional
  1859. // @ts-expect-error
  1860. expectString(instance.$props.actionText)