defineComponent.test-d.tsx 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080
  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. // #4051
  459. describe('type inference w/ empty prop object', () => {
  460. const MyComponent = defineComponent({
  461. props: {},
  462. setup(props) {
  463. return {}
  464. },
  465. render() {},
  466. })
  467. expectType<JSX.Element>(<MyComponent />)
  468. // AllowedComponentProps
  469. expectType<JSX.Element>(<MyComponent class={'foo'} />)
  470. // ComponentCustomProps
  471. expectType<JSX.Element>(<MyComponent custom={1} />)
  472. // VNodeProps
  473. expectType<JSX.Element>(<MyComponent key="1" />)
  474. // @ts-expect-error
  475. expectError(<MyComponent other="other" />)
  476. })
  477. describe('with mixins', () => {
  478. const MixinA = defineComponent({
  479. emits: ['bar'],
  480. props: {
  481. aP1: {
  482. type: String,
  483. default: 'aP1',
  484. },
  485. aP2: Boolean,
  486. },
  487. data() {
  488. return {
  489. a: 1,
  490. }
  491. },
  492. })
  493. const MixinB = defineComponent({
  494. props: ['bP1', 'bP2'],
  495. data() {
  496. return {
  497. b: 2,
  498. }
  499. },
  500. })
  501. const MixinC = defineComponent({
  502. data() {
  503. return {
  504. c: 3,
  505. }
  506. },
  507. })
  508. const MixinD = defineComponent({
  509. mixins: [MixinA],
  510. data() {
  511. //@ts-expect-error computed are not available on data()
  512. expectError<number>(this.dC1)
  513. //@ts-expect-error computed are not available on data()
  514. expectError<string>(this.dC2)
  515. return {
  516. d: 4,
  517. }
  518. },
  519. setup(props) {
  520. expectType<string>(props.aP1)
  521. },
  522. computed: {
  523. dC1() {
  524. return this.d + this.a
  525. },
  526. dC2() {
  527. return this.aP1 + 'dC2'
  528. },
  529. },
  530. })
  531. const MyComponent = defineComponent({
  532. mixins: [MixinA, MixinB, MixinC, MixinD],
  533. emits: ['click'],
  534. props: {
  535. // required should make property non-void
  536. z: {
  537. type: String,
  538. required: true,
  539. },
  540. },
  541. data(vm) {
  542. expectType<number>(vm.a)
  543. expectType<number>(vm.b)
  544. expectType<number>(vm.c)
  545. expectType<number>(vm.d)
  546. // should also expose declared props on `this`
  547. expectType<number>(this.a)
  548. expectType<string>(this.aP1)
  549. expectType<boolean | undefined>(this.aP2)
  550. expectType<number>(this.b)
  551. expectType<any>(this.bP1)
  552. expectType<number>(this.c)
  553. expectType<number>(this.d)
  554. return {}
  555. },
  556. setup(props) {
  557. expectType<string>(props.z)
  558. // props
  559. expectType<((...args: any[]) => any) | undefined>(props.onClick)
  560. // from MixinA
  561. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  562. expectType<string>(props.aP1)
  563. expectType<boolean | undefined>(props.aP2)
  564. expectType<any>(props.bP1)
  565. expectType<any>(props.bP2)
  566. expectType<string>(props.z)
  567. },
  568. render() {
  569. const props = this.$props
  570. // props
  571. expectType<((...args: any[]) => any) | undefined>(props.onClick)
  572. // from MixinA
  573. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  574. expectType<string>(props.aP1)
  575. expectType<boolean | undefined>(props.aP2)
  576. expectType<any>(props.bP1)
  577. expectType<any>(props.bP2)
  578. expectType<string>(props.z)
  579. const data = this.$data
  580. expectType<number>(data.a)
  581. expectType<number>(data.b)
  582. expectType<number>(data.c)
  583. expectType<number>(data.d)
  584. // should also expose declared props on `this`
  585. expectType<number>(this.a)
  586. expectType<string>(this.aP1)
  587. expectType<boolean | undefined>(this.aP2)
  588. expectType<number>(this.b)
  589. expectType<any>(this.bP1)
  590. expectType<number>(this.c)
  591. expectType<number>(this.d)
  592. expectType<number>(this.dC1)
  593. expectType<string>(this.dC2)
  594. // props should be readonly
  595. // @ts-expect-error
  596. this.aP1 = 'new'
  597. // @ts-expect-error
  598. this.z = 1
  599. // props on `this` should be readonly
  600. // @ts-expect-error
  601. this.bP1 = 1
  602. // string value can not assigned to number type value
  603. // @ts-expect-error
  604. this.c = '1'
  605. // setup context properties should be mutable
  606. this.d = 5
  607. return null
  608. },
  609. })
  610. // Test TSX
  611. expectType<JSX.Element>(
  612. <MyComponent aP1={'aP'} aP2 bP1={1} bP2={[1, 2]} z={'z'} />,
  613. )
  614. // missing required props
  615. // @ts-expect-error
  616. ;<MyComponent />
  617. // wrong prop types
  618. // @ts-expect-error
  619. ;<MyComponent aP1="ap" aP2={'wrong type'} bP1="b" z={'z'} />
  620. // @ts-expect-error
  621. ;<MyComponent aP1={1} bP2={[1]} />
  622. })
  623. describe('with extends', () => {
  624. const Base = defineComponent({
  625. props: {
  626. aP1: Boolean,
  627. aP2: {
  628. type: Number,
  629. default: 2,
  630. },
  631. },
  632. data() {
  633. return {
  634. a: 1,
  635. }
  636. },
  637. computed: {
  638. c(): number {
  639. return this.aP2 + this.a
  640. },
  641. },
  642. })
  643. const MyComponent = defineComponent({
  644. extends: Base,
  645. props: {
  646. // required should make property non-void
  647. z: {
  648. type: String,
  649. required: true,
  650. },
  651. },
  652. render() {
  653. const props = this.$props
  654. // props
  655. expectType<boolean | undefined>(props.aP1)
  656. expectType<number>(props.aP2)
  657. expectType<string>(props.z)
  658. const data = this.$data
  659. expectType<number>(data.a)
  660. // should also expose declared props on `this`
  661. expectType<number>(this.a)
  662. expectType<boolean | undefined>(this.aP1)
  663. expectType<number>(this.aP2)
  664. // setup context properties should be mutable
  665. this.a = 5
  666. return null
  667. },
  668. })
  669. // Test TSX
  670. expectType<JSX.Element>(<MyComponent aP2={3} aP1 z={'z'} />)
  671. // missing required props
  672. // @ts-expect-error
  673. ;<MyComponent />
  674. // wrong prop types
  675. // @ts-expect-error
  676. ;<MyComponent aP2={'wrong type'} z={'z'} />
  677. // @ts-expect-error
  678. ;<MyComponent aP1={3} />
  679. })
  680. describe('extends with mixins', () => {
  681. const Mixin = defineComponent({
  682. emits: ['bar'],
  683. props: {
  684. mP1: {
  685. type: String,
  686. default: 'mP1',
  687. },
  688. mP2: Boolean,
  689. mP3: {
  690. type: Boolean,
  691. required: true,
  692. },
  693. },
  694. data() {
  695. return {
  696. a: 1,
  697. }
  698. },
  699. })
  700. const Base = defineComponent({
  701. emits: ['foo'],
  702. props: {
  703. p1: Boolean,
  704. p2: {
  705. type: Number,
  706. default: 2,
  707. },
  708. p3: {
  709. type: Boolean,
  710. required: true,
  711. },
  712. },
  713. data() {
  714. return {
  715. b: 2,
  716. }
  717. },
  718. computed: {
  719. c(): number {
  720. return this.p2 + this.b
  721. },
  722. },
  723. })
  724. const MyComponent = defineComponent({
  725. extends: Base,
  726. mixins: [Mixin],
  727. emits: ['click'],
  728. props: {
  729. // required should make property non-void
  730. z: {
  731. type: String,
  732. required: true,
  733. },
  734. },
  735. render() {
  736. const props = this.$props
  737. // props
  738. expectType<((...args: any[]) => any) | undefined>(props.onClick)
  739. // from Mixin
  740. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  741. // from Base
  742. expectType<((...args: any[]) => any) | undefined>(props.onFoo)
  743. expectType<boolean | undefined>(props.p1)
  744. expectType<number>(props.p2)
  745. expectType<string>(props.z)
  746. expectType<string>(props.mP1)
  747. expectType<boolean | undefined>(props.mP2)
  748. const data = this.$data
  749. expectType<number>(data.a)
  750. expectType<number>(data.b)
  751. // should also expose declared props on `this`
  752. expectType<number>(this.a)
  753. expectType<number>(this.b)
  754. expectType<boolean | undefined>(this.p1)
  755. expectType<number>(this.p2)
  756. expectType<string>(this.mP1)
  757. expectType<boolean | undefined>(this.mP2)
  758. // setup context properties should be mutable
  759. this.a = 5
  760. return null
  761. },
  762. })
  763. // Test TSX
  764. expectType<JSX.Element>(<MyComponent mP1="p1" mP2 mP3 p1 p2={1} p3 z={'z'} />)
  765. // mP1, mP2, p1, and p2 have default value. these are not required
  766. expectType<JSX.Element>(<MyComponent mP3 p3 z={'z'} />)
  767. // missing required props
  768. // @ts-expect-error
  769. ;<MyComponent mP3 p3 /* z='z' */ />
  770. // missing required props from mixin
  771. // @ts-expect-error
  772. ;<MyComponent /* mP3 */ p3 z="z" />
  773. // missing required props from extends
  774. // @ts-expect-error
  775. ;<MyComponent mP3 /* p3 */ z="z" />
  776. // wrong prop types
  777. // @ts-expect-error
  778. ;<MyComponent p2={'wrong type'} z={'z'} />
  779. // @ts-expect-error
  780. ;<MyComponent mP1={3} />
  781. // #3468
  782. const CompWithD = defineComponent({
  783. data() {
  784. return { foo: 1 }
  785. },
  786. })
  787. const CompWithC = defineComponent({
  788. computed: {
  789. foo() {
  790. return 1
  791. },
  792. },
  793. })
  794. const CompWithM = defineComponent({ methods: { foo() {} } })
  795. const CompEmpty = defineComponent({})
  796. defineComponent({
  797. mixins: [CompWithD, CompEmpty],
  798. mounted() {
  799. expectType<number>(this.foo)
  800. },
  801. })
  802. defineComponent({
  803. mixins: [CompWithC, CompEmpty],
  804. mounted() {
  805. expectType<number>(this.foo)
  806. },
  807. })
  808. defineComponent({
  809. mixins: [CompWithM, CompEmpty],
  810. mounted() {
  811. expectType<() => void>(this.foo)
  812. },
  813. })
  814. })
  815. describe('compatibility w/ createApp', () => {
  816. const comp = defineComponent({})
  817. createApp(comp).mount('#hello')
  818. const comp2 = defineComponent({
  819. props: { foo: String },
  820. })
  821. createApp(comp2).mount('#hello')
  822. const comp3 = defineComponent({
  823. setup() {
  824. return {
  825. a: 1,
  826. }
  827. },
  828. })
  829. createApp(comp3).mount('#hello')
  830. })
  831. describe('defineComponent', () => {
  832. describe('should accept components defined with defineComponent', () => {
  833. const comp = defineComponent({})
  834. defineComponent({
  835. components: { comp },
  836. })
  837. })
  838. describe('should accept class components with receiving constructor arguments', () => {
  839. class Comp {
  840. static __vccOpts = {}
  841. constructor(_props: { foo: string }) {}
  842. }
  843. defineComponent({
  844. components: { Comp },
  845. })
  846. })
  847. })
  848. describe('emits', () => {
  849. // Note: for TSX inference, ideally we want to map emits to onXXX props,
  850. // but that requires type-level string constant concatenation as suggested in
  851. // https://github.com/Microsoft/TypeScript/issues/12754
  852. // The workaround for TSX users is instead of using emits, declare onXXX props
  853. // and call them instead. Since `v-on:click` compiles to an `onClick` prop,
  854. // this would also support other users consuming the component in templates
  855. // with `v-on` listeners.
  856. // with object emits
  857. defineComponent({
  858. emits: {
  859. click: (n: number) => typeof n === 'number',
  860. input: (b: string) => b.length > 1,
  861. Focus: (f: boolean) => !!f,
  862. },
  863. setup(props, { emit }) {
  864. expectType<((n: number) => boolean) | undefined>(props.onClick)
  865. expectType<((b: string) => boolean) | undefined>(props.onInput)
  866. expectType<((f: boolean) => boolean) | undefined>(props.onFocus)
  867. emit('click', 1)
  868. emit('input', 'foo')
  869. emit('Focus', true)
  870. // @ts-expect-error
  871. emit('nope')
  872. // @ts-expect-error
  873. emit('click')
  874. // @ts-expect-error
  875. emit('click', 'foo')
  876. // @ts-expect-error
  877. emit('input')
  878. // @ts-expect-error
  879. emit('input', 1)
  880. // @ts-expect-error
  881. emit('focus')
  882. // @ts-expect-error
  883. emit('focus', true)
  884. },
  885. created() {
  886. this.$emit('click', 1)
  887. this.$emit('input', 'foo')
  888. // @ts-expect-error
  889. this.$emit('nope')
  890. // @ts-expect-error
  891. this.$emit('click')
  892. // @ts-expect-error
  893. this.$emit('click', 'foo')
  894. // @ts-expect-error
  895. this.$emit('input')
  896. // @ts-expect-error
  897. this.$emit('input', 1)
  898. // @ts-expect-error
  899. this.$emit('focus')
  900. // @ts-expect-error
  901. this.$emit('focus', true)
  902. },
  903. mounted() {
  904. // #3599
  905. this.$nextTick(function () {
  906. // this should be bound to this instance
  907. this.$emit('click', 1)
  908. this.$emit('input', 'foo')
  909. // @ts-expect-error
  910. this.$emit('nope')
  911. // @ts-expect-error
  912. this.$emit('click')
  913. // @ts-expect-error
  914. this.$emit('click', 'foo')
  915. // @ts-expect-error
  916. this.$emit('input')
  917. // @ts-expect-error
  918. this.$emit('input', 1)
  919. // @ts-expect-error
  920. this.$emit('focus')
  921. // @ts-expect-error
  922. this.$emit('focus', true)
  923. })
  924. },
  925. })
  926. // with array emits
  927. defineComponent({
  928. emits: ['foo', 'bar'],
  929. setup(props, { emit }) {
  930. expectType<((...args: any[]) => any) | undefined>(props.onFoo)
  931. expectType<((...args: any[]) => any) | undefined>(props.onBar)
  932. emit('foo')
  933. emit('foo', 123)
  934. emit('bar')
  935. // @ts-expect-error
  936. emit('nope')
  937. },
  938. created() {
  939. this.$emit('foo')
  940. this.$emit('foo', 123)
  941. this.$emit('bar')
  942. // @ts-expect-error
  943. this.$emit('nope')
  944. },
  945. })
  946. // with tsx
  947. const Component = defineComponent({
  948. emits: {
  949. click: (n: number) => typeof n === 'number',
  950. },
  951. setup(props, { emit }) {
  952. expectType<((n: number) => any) | undefined>(props.onClick)
  953. emit('click', 1)
  954. // @ts-expect-error
  955. emit('click')
  956. // @ts-expect-error
  957. emit('click', 'foo')
  958. },
  959. })
  960. defineComponent({
  961. render() {
  962. return (
  963. <Component
  964. onClick={(n: number) => {
  965. return n + 1
  966. }}
  967. />
  968. )
  969. },
  970. })
  971. // #11803 manual props annotation in setup()
  972. const Hello = defineComponent({
  973. name: 'HelloWorld',
  974. inheritAttrs: false,
  975. props: { foo: String },
  976. emits: {
  977. customClick: (args: string) => typeof args === 'string',
  978. },
  979. setup(props: { foo?: string }) {},
  980. })
  981. ;<Hello onCustomClick={() => {}} />
  982. // without emits
  983. defineComponent({
  984. setup(props, { emit }) {
  985. emit('test', 1)
  986. emit('test')
  987. },
  988. })
  989. // emit should be valid when ComponentPublicInstance is used.
  990. const instance = {} as ComponentPublicInstance
  991. instance.$emit('test', 1)
  992. instance.$emit('test')
  993. // `this` should be void inside of emits validators
  994. defineComponent({
  995. props: ['bar'],
  996. emits: {
  997. foo(): boolean {
  998. // @ts-expect-error
  999. return this.bar === 3
  1000. },
  1001. },
  1002. })
  1003. })
  1004. describe('inject', () => {
  1005. // with object inject
  1006. defineComponent({
  1007. props: {
  1008. a: String,
  1009. },
  1010. inject: {
  1011. foo: 'foo',
  1012. bar: 'bar',
  1013. },
  1014. created() {
  1015. expectType<unknown>(this.foo)
  1016. expectType<unknown>(this.bar)
  1017. // @ts-expect-error
  1018. this.foobar = 1
  1019. },
  1020. })
  1021. // with array inject
  1022. defineComponent({
  1023. props: ['a', 'b'],
  1024. inject: ['foo', 'bar'],
  1025. created() {
  1026. expectType<unknown>(this.foo)
  1027. expectType<unknown>(this.bar)
  1028. // @ts-expect-error
  1029. this.foobar = 1
  1030. },
  1031. })
  1032. // with no props
  1033. defineComponent({
  1034. inject: {
  1035. foo: {
  1036. from: 'pfoo',
  1037. default: 'foo',
  1038. },
  1039. bar: {
  1040. from: 'pbar',
  1041. default: 'bar',
  1042. },
  1043. },
  1044. created() {
  1045. expectType<unknown>(this.foo)
  1046. expectType<unknown>(this.bar)
  1047. // @ts-expect-error
  1048. this.foobar = 1
  1049. },
  1050. })
  1051. // without inject
  1052. defineComponent({
  1053. props: ['a', 'b'],
  1054. created() {
  1055. // @ts-expect-error
  1056. this.foo = 1
  1057. // @ts-expect-error
  1058. this.bar = 1
  1059. },
  1060. })
  1061. })
  1062. describe('componentOptions setup should be `SetupContext`', () => {
  1063. expectType<ComponentOptions['setup']>(
  1064. {} as (props: Record<string, any>, ctx: SetupContext) => any,
  1065. )
  1066. })
  1067. describe('extract instance type', () => {
  1068. const Base = defineComponent({
  1069. props: {
  1070. baseA: {
  1071. type: Number,
  1072. default: 1,
  1073. },
  1074. },
  1075. })
  1076. const MixinA = defineComponent({
  1077. props: {
  1078. mA: {
  1079. type: String,
  1080. default: '',
  1081. },
  1082. },
  1083. })
  1084. const CompA = defineComponent({
  1085. extends: Base,
  1086. mixins: [MixinA],
  1087. props: {
  1088. a: {
  1089. type: Boolean,
  1090. default: false,
  1091. },
  1092. b: {
  1093. type: String,
  1094. required: true,
  1095. },
  1096. c: Number,
  1097. },
  1098. })
  1099. const compA = {} as InstanceType<typeof CompA>
  1100. expectType<boolean>(compA.a)
  1101. expectType<string>(compA.b)
  1102. expectType<number | undefined>(compA.c)
  1103. // mixins
  1104. expectType<string>(compA.mA)
  1105. // extends
  1106. expectType<number>(compA.baseA)
  1107. // @ts-expect-error
  1108. compA.a = true
  1109. // @ts-expect-error
  1110. compA.b = 'foo'
  1111. // @ts-expect-error
  1112. compA.c = 1
  1113. // @ts-expect-error
  1114. compA.mA = 'foo'
  1115. // @ts-expect-error
  1116. compA.baseA = 1
  1117. })
  1118. describe('async setup', () => {
  1119. type GT = string & { __brand: unknown }
  1120. const Comp = defineComponent({
  1121. async setup() {
  1122. // setup context
  1123. return {
  1124. a: ref(1),
  1125. b: {
  1126. c: ref('hi'),
  1127. },
  1128. d: reactive({
  1129. e: ref('hello' as GT),
  1130. }),
  1131. }
  1132. },
  1133. render() {
  1134. // assert setup context unwrapping
  1135. expectType<number>(this.a)
  1136. expectType<string>(this.b.c.value)
  1137. expectType<GT>(this.d.e)
  1138. // setup context properties should be mutable
  1139. this.a = 2
  1140. },
  1141. })
  1142. const vm = {} as InstanceType<typeof Comp>
  1143. // assert setup context unwrapping
  1144. expectType<number>(vm.a)
  1145. expectType<string>(vm.b.c.value)
  1146. expectType<GT>(vm.d.e)
  1147. // setup context properties should be mutable
  1148. vm.a = 2
  1149. })
  1150. // #5948
  1151. describe('DefineComponent should infer correct types when assigning to Component', () => {
  1152. let component: Component
  1153. component = defineComponent({
  1154. setup(_, { attrs, slots }) {
  1155. // @ts-expect-error should not be any
  1156. expectType<[]>(attrs)
  1157. // @ts-expect-error should not be any
  1158. expectType<[]>(slots)
  1159. },
  1160. })
  1161. expectType<Component>(component)
  1162. })
  1163. // #5969
  1164. describe('should allow to assign props', () => {
  1165. const Child = defineComponent({
  1166. props: {
  1167. bar: String,
  1168. },
  1169. })
  1170. const Parent = defineComponent({
  1171. props: {
  1172. ...Child.props,
  1173. foo: String,
  1174. },
  1175. })
  1176. const child = new Child()
  1177. expectType<JSX.Element>(<Parent {...child.$props} />)
  1178. })
  1179. // #6052
  1180. describe('prop starting with `on*` is broken', () => {
  1181. defineComponent({
  1182. props: {
  1183. onX: {
  1184. type: Function as PropType<(a: 1) => void>,
  1185. required: true,
  1186. },
  1187. },
  1188. setup(props) {
  1189. expectType<(a: 1) => void>(props.onX)
  1190. props.onX(1)
  1191. },
  1192. })
  1193. defineComponent({
  1194. props: {
  1195. onX: {
  1196. type: Function as PropType<(a: 1) => void>,
  1197. required: true,
  1198. },
  1199. },
  1200. emits: {
  1201. test: (a: 1) => true,
  1202. },
  1203. setup(props) {
  1204. expectType<(a: 1) => void>(props.onX)
  1205. expectType<undefined | ((a: 1) => any)>(props.onTest)
  1206. },
  1207. })
  1208. })
  1209. describe('function syntax w/ generics', () => {
  1210. const Comp = defineComponent(
  1211. // TODO: babel plugin to auto infer runtime props options from type
  1212. // similar to defineProps<{...}>()
  1213. <T extends string | number>(props: { msg: T; list: T[] }) => {
  1214. // use Composition API here like in <script setup>
  1215. const count = ref(0)
  1216. return () => (
  1217. // return a render function (both JSX and h() works)
  1218. <div>
  1219. {props.msg} {count.value}
  1220. </div>
  1221. )
  1222. },
  1223. )
  1224. expectType<JSX.Element>(<Comp msg="fse" list={['foo']} />)
  1225. expectType<JSX.Element>(<Comp msg={123} list={[123]} />)
  1226. expectType<JSX.Element>(
  1227. // @ts-expect-error missing prop
  1228. <Comp msg={123} />,
  1229. )
  1230. expectType<JSX.Element>(
  1231. // @ts-expect-error generics don't match
  1232. <Comp msg="fse" list={[123]} />,
  1233. )
  1234. expectType<JSX.Element>(
  1235. // @ts-expect-error generics don't match
  1236. <Comp msg={123} list={['123']} />,
  1237. )
  1238. })
  1239. describe('function syntax w/ emits', () => {
  1240. const Foo = defineComponent(
  1241. (props: { msg: string }, ctx) => {
  1242. ctx.emit('foo')
  1243. // @ts-expect-error
  1244. ctx.emit('bar')
  1245. return () => {}
  1246. },
  1247. {
  1248. emits: ['foo'],
  1249. },
  1250. )
  1251. expectType<JSX.Element>(<Foo msg="hi" onFoo={() => {}} />)
  1252. // @ts-expect-error
  1253. expectType<JSX.Element>(<Foo msg="hi" onBar={() => {}} />)
  1254. defineComponent(
  1255. (props: { msg: string }, ctx) => {
  1256. ctx.emit('foo', 'hi')
  1257. // @ts-expect-error
  1258. ctx.emit('foo')
  1259. // @ts-expect-error
  1260. ctx.emit('bar')
  1261. return () => {}
  1262. },
  1263. {
  1264. emits: {
  1265. foo: (a: string) => true,
  1266. },
  1267. },
  1268. )
  1269. })
  1270. describe('function syntax w/ runtime props', () => {
  1271. // with runtime props, the runtime props must match
  1272. // manual type declaration
  1273. defineComponent(
  1274. (_props: { msg: string }) => {
  1275. return () => {}
  1276. },
  1277. {
  1278. props: ['msg'],
  1279. },
  1280. )
  1281. defineComponent(
  1282. <T extends string>(_props: { msg: T }) => {
  1283. return () => {}
  1284. },
  1285. {
  1286. props: ['msg'],
  1287. },
  1288. )
  1289. defineComponent(
  1290. <T extends string>(_props: { msg: T }) => {
  1291. return () => {}
  1292. },
  1293. {
  1294. props: {
  1295. msg: String,
  1296. },
  1297. },
  1298. )
  1299. // @ts-expect-error string prop names don't match
  1300. defineComponent(
  1301. (_props: { msg: string }) => {
  1302. return () => {}
  1303. },
  1304. {
  1305. props: ['bar'],
  1306. },
  1307. )
  1308. defineComponent(
  1309. (_props: { msg: string }) => {
  1310. return () => {}
  1311. },
  1312. {
  1313. props: {
  1314. // @ts-expect-error prop type mismatch
  1315. msg: Number,
  1316. },
  1317. },
  1318. )
  1319. // @ts-expect-error prop keys don't match
  1320. defineComponent(
  1321. (_props: { msg: string }, ctx) => {
  1322. return () => {}
  1323. },
  1324. {
  1325. props: {
  1326. msg: String,
  1327. bar: String,
  1328. },
  1329. },
  1330. )
  1331. })
  1332. // check if defineComponent can be exported
  1333. export default {
  1334. // function components
  1335. a: defineComponent(_ => () => h('div')),
  1336. // no props
  1337. b: defineComponent({
  1338. data() {
  1339. return {}
  1340. },
  1341. }),
  1342. c: defineComponent({
  1343. props: ['a'],
  1344. }),
  1345. d: defineComponent({
  1346. props: {
  1347. a: Number,
  1348. },
  1349. }),
  1350. }
  1351. describe('slots', () => {
  1352. const comp1 = defineComponent({
  1353. slots: Object as SlotsType<{
  1354. default: { foo: string; bar: number }
  1355. optional?: { data: string }
  1356. undefinedScope: undefined | { data: string }
  1357. optionalUndefinedScope?: undefined | { data: string }
  1358. }>,
  1359. setup(props, { slots }) {
  1360. expectType<(scope: { foo: string; bar: number }) => VNode[]>(
  1361. slots.default,
  1362. )
  1363. expectType<((scope: { data: string }) => VNode[]) | undefined>(
  1364. slots.optional,
  1365. )
  1366. slots.default({ foo: 'foo', bar: 1 })
  1367. // @ts-expect-error it's optional
  1368. slots.optional({ data: 'foo' })
  1369. slots.optional?.({ data: 'foo' })
  1370. expectType<{
  1371. (): VNode[]
  1372. (scope: undefined | { data: string }): VNode[]
  1373. }>(slots.undefinedScope)
  1374. expectType<
  1375. | { (): VNode[]; (scope: undefined | { data: string }): VNode[] }
  1376. | undefined
  1377. >(slots.optionalUndefinedScope)
  1378. slots.default({ foo: 'foo', bar: 1 })
  1379. // @ts-expect-error it's optional
  1380. slots.optional({ data: 'foo' })
  1381. slots.optional?.({ data: 'foo' })
  1382. slots.undefinedScope()
  1383. slots.undefinedScope(undefined)
  1384. // @ts-expect-error
  1385. slots.undefinedScope('foo')
  1386. slots.optionalUndefinedScope?.()
  1387. slots.optionalUndefinedScope?.(undefined)
  1388. slots.optionalUndefinedScope?.({ data: 'foo' })
  1389. // @ts-expect-error
  1390. slots.optionalUndefinedScope()
  1391. // @ts-expect-error
  1392. slots.optionalUndefinedScope?.('foo')
  1393. expectType<typeof slots | undefined>(new comp1().$slots)
  1394. },
  1395. })
  1396. const comp2 = defineComponent({
  1397. setup(props, { slots }) {
  1398. // unknown slots
  1399. expectType<Slots>(slots)
  1400. expectType<((...args: any[]) => VNode[]) | undefined>(slots.default)
  1401. },
  1402. })
  1403. expectType<Slots | undefined>(new comp2().$slots)
  1404. })
  1405. // #5885
  1406. describe('should work when props type is incompatible with setup returned type ', () => {
  1407. type SizeType = 'small' | 'big'
  1408. const Comp = defineComponent({
  1409. props: {
  1410. size: {
  1411. type: String as PropType<SizeType>,
  1412. required: true,
  1413. },
  1414. },
  1415. setup(props) {
  1416. expectType<SizeType>(props.size)
  1417. return {
  1418. size: 1,
  1419. }
  1420. },
  1421. })
  1422. type CompInstance = InstanceType<typeof Comp>
  1423. const CompA = {} as CompInstance
  1424. expectType<ComponentPublicInstance>(CompA)
  1425. expectType<number>(CompA.size)
  1426. expectType<SizeType>(CompA.$props.size)
  1427. })
  1428. describe('withKeys and withModifiers as pro', () => {
  1429. const onKeydown = withKeys(e => {}, [''])
  1430. const onClick = withModifiers(e => {}, [])
  1431. ;<input onKeydown={onKeydown} onClick={onClick} />
  1432. })
  1433. // #3367 expose components types
  1434. describe('expose component types', () => {
  1435. const child = defineComponent({
  1436. props: {
  1437. a: String,
  1438. },
  1439. })
  1440. const parent = defineComponent({
  1441. components: {
  1442. child,
  1443. child2: {
  1444. template: `<div></div>`,
  1445. },
  1446. },
  1447. })
  1448. expectType<typeof child>(parent.components!.child)
  1449. expectType<Component>(parent.components!.child2)
  1450. // global components
  1451. expectType<Readonly<KeepAliveProps>>(
  1452. new parent.components!.KeepAlive().$props,
  1453. )
  1454. expectType<Readonly<KeepAliveProps>>(new child.components!.KeepAlive().$props)
  1455. // runtime-dom components
  1456. expectType<Readonly<TransitionProps>>(
  1457. new parent.components!.Transition().$props,
  1458. )
  1459. expectType<Readonly<TransitionProps>>(
  1460. new child.components!.Transition().$props,
  1461. )
  1462. })
  1463. describe('directive typing', () => {
  1464. const customDirective: Directive = {
  1465. created(_) {},
  1466. }
  1467. const comp = defineComponent({
  1468. props: {
  1469. a: String,
  1470. },
  1471. directives: {
  1472. customDirective,
  1473. localDirective: {
  1474. created(_, { arg }) {
  1475. expectType<string | undefined>(arg)
  1476. },
  1477. },
  1478. },
  1479. })
  1480. expectType<typeof customDirective>(comp.directives!.customDirective)
  1481. expectType<Directive>(comp.directives!.localDirective)
  1482. // global directive
  1483. expectType<typeof vShow>(comp.directives!.vShow)
  1484. })
  1485. describe('expose typing', () => {
  1486. const Comp = defineComponent({
  1487. expose: ['a', 'b'],
  1488. props: {
  1489. some: String,
  1490. },
  1491. data() {
  1492. return { a: 1, b: '2', c: 1 }
  1493. },
  1494. })
  1495. expectType<Array<'a' | 'b'>>(Comp.expose!)
  1496. const vm = new Comp()
  1497. // internal should still be exposed
  1498. vm.$props
  1499. expectType<number>(vm.a)
  1500. expectType<string>(vm.b)
  1501. // @ts-expect-error shouldn't be exposed
  1502. vm.c
  1503. })
  1504. import type {
  1505. AllowedComponentProps,
  1506. ComponentCustomProps,
  1507. ComponentInstance,
  1508. ComponentOptionsMixin,
  1509. DefineComponent,
  1510. Directive,
  1511. EmitsOptions,
  1512. ExtractPropTypes,
  1513. KeepAliveProps,
  1514. TransitionProps,
  1515. VNodeProps,
  1516. vShow,
  1517. } from 'vue'
  1518. // code generated by tsc / vue-tsc, make sure this continues to work
  1519. // so we don't accidentally change the args order of DefineComponent
  1520. declare const MyButton: DefineComponent<
  1521. {},
  1522. () => JSX.Element,
  1523. {},
  1524. {},
  1525. {},
  1526. ComponentOptionsMixin,
  1527. ComponentOptionsMixin,
  1528. EmitsOptions,
  1529. string,
  1530. VNodeProps & AllowedComponentProps & ComponentCustomProps,
  1531. Readonly<ExtractPropTypes<{}>>,
  1532. {},
  1533. {}
  1534. >
  1535. ;<MyButton class="x" />
  1536. describe('__typeProps backdoor for union type for conditional props', () => {
  1537. interface CommonProps {
  1538. size?: 'xl' | 'l' | 'm' | 's' | 'xs'
  1539. }
  1540. type ConditionalProps =
  1541. | {
  1542. color?: 'normal' | 'primary' | 'secondary'
  1543. appearance?: 'normal' | 'outline' | 'text'
  1544. }
  1545. | {
  1546. color: 'white'
  1547. appearance: 'outline'
  1548. }
  1549. type Props = CommonProps & ConditionalProps
  1550. const Comp = defineComponent({
  1551. __typeProps: {} as Props,
  1552. })
  1553. // @ts-expect-error
  1554. ;<Comp color="white" />
  1555. // @ts-expect-error
  1556. ;<Comp color="white" appearance="normal" />
  1557. ;<Comp color="white" appearance="outline" />
  1558. const c = new Comp()
  1559. // @ts-expect-error
  1560. c.$props = { color: 'white' }
  1561. // @ts-expect-error
  1562. c.$props = { color: 'white', appearance: 'text' }
  1563. c.$props = { color: 'white', appearance: 'outline' }
  1564. })
  1565. describe('__typeEmits backdoor, 3.3+ object syntax', () => {
  1566. type Emits = {
  1567. change: [id: number]
  1568. update: [value: string]
  1569. }
  1570. const Comp = defineComponent({
  1571. __typeEmits: {} as Emits,
  1572. mounted() {
  1573. this.$props.onChange?.(123)
  1574. // @ts-expect-error
  1575. this.$props.onChange?.('123')
  1576. this.$props.onUpdate?.('foo')
  1577. // @ts-expect-error
  1578. this.$props.onUpdate?.(123)
  1579. // @ts-expect-error
  1580. this.$emit('foo')
  1581. this.$emit('change', 123)
  1582. // @ts-expect-error
  1583. this.$emit('change', '123')
  1584. this.$emit('update', 'test')
  1585. // @ts-expect-error
  1586. this.$emit('update', 123)
  1587. },
  1588. })
  1589. ;<Comp onChange={id => id.toFixed(2)} />
  1590. ;<Comp onUpdate={id => id.toUpperCase()} />
  1591. // @ts-expect-error
  1592. ;<Comp onChange={id => id.slice(1)} />
  1593. // @ts-expect-error
  1594. ;<Comp onUpdate={id => id.toFixed(2)} />
  1595. const c = new Comp()
  1596. // @ts-expect-error
  1597. c.$emit('foo')
  1598. c.$emit('change', 123)
  1599. // @ts-expect-error
  1600. c.$emit('change', '123')
  1601. c.$emit('update', 'test')
  1602. // @ts-expect-error
  1603. c.$emit('update', 123)
  1604. })
  1605. describe('__typeEmits backdoor, call signature syntax', () => {
  1606. type Emits = {
  1607. (e: 'change', id: number): void
  1608. (e: 'update', value: string): void
  1609. }
  1610. const Comp = defineComponent({
  1611. __typeEmits: {} as Emits,
  1612. mounted() {
  1613. this.$props.onChange?.(123)
  1614. // @ts-expect-error
  1615. this.$props.onChange?.('123')
  1616. this.$props.onUpdate?.('foo')
  1617. // @ts-expect-error
  1618. this.$props.onUpdate?.(123)
  1619. // @ts-expect-error
  1620. this.$emit('foo')
  1621. this.$emit('change', 123)
  1622. // @ts-expect-error
  1623. this.$emit('change', '123')
  1624. this.$emit('update', 'test')
  1625. // @ts-expect-error
  1626. this.$emit('update', 123)
  1627. },
  1628. })
  1629. ;<Comp onChange={id => id.toFixed(2)} />
  1630. ;<Comp onUpdate={id => id.toUpperCase()} />
  1631. // @ts-expect-error
  1632. ;<Comp onChange={id => id.slice(1)} />
  1633. // @ts-expect-error
  1634. ;<Comp onUpdate={id => id.toFixed(2)} />
  1635. const c = new Comp()
  1636. // @ts-expect-error
  1637. c.$emit('foo')
  1638. c.$emit('change', 123)
  1639. // @ts-expect-error
  1640. c.$emit('change', '123')
  1641. c.$emit('update', 'test')
  1642. // @ts-expect-error
  1643. c.$emit('update', 123)
  1644. })
  1645. describe('__typeRefs backdoor, object syntax', () => {
  1646. type Refs = {
  1647. foo: number
  1648. }
  1649. const Parent = defineComponent({
  1650. __typeRefs: {} as { child: ComponentInstance<typeof Child> },
  1651. })
  1652. const Child = defineComponent({
  1653. __typeRefs: {} as Refs,
  1654. })
  1655. const c = new Parent()
  1656. const refs = c.$refs
  1657. expectType<ComponentInstance<typeof Child>>(refs.child)
  1658. expectType<number>(refs.child.$refs.foo)
  1659. })
  1660. describe('__typeEl backdoor', () => {
  1661. const Comp = defineComponent({
  1662. __typeEl: {} as HTMLAnchorElement,
  1663. })
  1664. const c = new Comp()
  1665. expectType<HTMLAnchorElement>(c.$el)
  1666. })
  1667. defineComponent({
  1668. props: {
  1669. foo: [String, null],
  1670. },
  1671. setup(props) {
  1672. expectType<IsAny<typeof props.foo>>(false)
  1673. expectType<string | null | undefined>(props.foo)
  1674. },
  1675. })
  1676. import type * as vue from 'vue'
  1677. interface ErrorMessageSlotProps {
  1678. message: string | undefined
  1679. }
  1680. /**
  1681. * #10842
  1682. * component types generated by vue-tsc
  1683. * relying on legacy CreateComponentPublicInstance signature
  1684. */
  1685. declare const ErrorMessage: {
  1686. new (...args: any[]): vue.CreateComponentPublicInstance<
  1687. Readonly<
  1688. vue.ExtractPropTypes<{
  1689. as: {
  1690. type: StringConstructor
  1691. default: any
  1692. }
  1693. name: {
  1694. type: StringConstructor
  1695. required: true
  1696. }
  1697. }>
  1698. >,
  1699. () =>
  1700. | VNode<
  1701. vue.RendererNode,
  1702. vue.RendererElement,
  1703. {
  1704. [key: string]: any
  1705. }
  1706. >
  1707. | vue.Slot<any>
  1708. | VNode<
  1709. vue.RendererNode,
  1710. vue.RendererElement,
  1711. {
  1712. [key: string]: any
  1713. }
  1714. >[]
  1715. | {
  1716. default: () => VNode<
  1717. vue.RendererNode,
  1718. vue.RendererElement,
  1719. {
  1720. [key: string]: any
  1721. }
  1722. >[]
  1723. },
  1724. unknown,
  1725. {},
  1726. {},
  1727. vue.ComponentOptionsMixin,
  1728. vue.ComponentOptionsMixin,
  1729. {},
  1730. vue.VNodeProps &
  1731. vue.AllowedComponentProps &
  1732. vue.ComponentCustomProps &
  1733. Readonly<
  1734. vue.ExtractPropTypes<{
  1735. as: {
  1736. type: StringConstructor
  1737. default: any
  1738. }
  1739. name: {
  1740. type: StringConstructor
  1741. required: true
  1742. }
  1743. }>
  1744. >,
  1745. {
  1746. as: string
  1747. },
  1748. true,
  1749. {},
  1750. {},
  1751. {
  1752. P: {}
  1753. B: {}
  1754. D: {}
  1755. C: {}
  1756. M: {}
  1757. Defaults: {}
  1758. },
  1759. Readonly<
  1760. vue.ExtractPropTypes<{
  1761. as: {
  1762. type: StringConstructor
  1763. default: any
  1764. }
  1765. name: {
  1766. type: StringConstructor
  1767. required: true
  1768. }
  1769. }>
  1770. >,
  1771. () =>
  1772. | VNode<
  1773. vue.RendererNode,
  1774. vue.RendererElement,
  1775. {
  1776. [key: string]: any
  1777. }
  1778. >
  1779. | vue.Slot<any>
  1780. | VNode<
  1781. vue.RendererNode,
  1782. vue.RendererElement,
  1783. {
  1784. [key: string]: any
  1785. }
  1786. >[]
  1787. | {
  1788. default: () => VNode<
  1789. vue.RendererNode,
  1790. vue.RendererElement,
  1791. {
  1792. [key: string]: any
  1793. }
  1794. >[]
  1795. },
  1796. {},
  1797. {},
  1798. {},
  1799. {
  1800. as: string
  1801. }
  1802. >
  1803. __isFragment?: never
  1804. __isTeleport?: never
  1805. __isSuspense?: never
  1806. } & vue.ComponentOptionsBase<
  1807. Readonly<
  1808. vue.ExtractPropTypes<{
  1809. as: {
  1810. type: StringConstructor
  1811. default: any
  1812. }
  1813. name: {
  1814. type: StringConstructor
  1815. required: true
  1816. }
  1817. }>
  1818. >,
  1819. () =>
  1820. | VNode<
  1821. vue.RendererNode,
  1822. vue.RendererElement,
  1823. {
  1824. [key: string]: any
  1825. }
  1826. >
  1827. | vue.Slot<any>
  1828. | VNode<
  1829. vue.RendererNode,
  1830. vue.RendererElement,
  1831. {
  1832. [key: string]: any
  1833. }
  1834. >[]
  1835. | {
  1836. default: () => VNode<
  1837. vue.RendererNode,
  1838. vue.RendererElement,
  1839. {
  1840. [key: string]: any
  1841. }
  1842. >[]
  1843. },
  1844. unknown,
  1845. {},
  1846. {},
  1847. vue.ComponentOptionsMixin,
  1848. vue.ComponentOptionsMixin,
  1849. {},
  1850. string,
  1851. {
  1852. as: string
  1853. },
  1854. {},
  1855. string,
  1856. {}
  1857. > &
  1858. vue.VNodeProps &
  1859. vue.AllowedComponentProps &
  1860. vue.ComponentCustomProps &
  1861. (new () => {
  1862. $slots: {
  1863. default: (arg: ErrorMessageSlotProps) => VNode[]
  1864. }
  1865. })
  1866. ;<ErrorMessage name="password" class="error" />
  1867. // #10843
  1868. createApp({}).component(
  1869. 'SomeComponent',
  1870. defineComponent({
  1871. props: {
  1872. title: String,
  1873. },
  1874. setup(props) {
  1875. expectType<string | undefined>(props.title)
  1876. return {}
  1877. },
  1878. }),
  1879. )
  1880. const Comp = defineComponent({
  1881. props: {
  1882. actionText: {
  1883. type: {} as PropType<string>,
  1884. default: 'Become a sponsor',
  1885. },
  1886. },
  1887. __typeProps: {} as {
  1888. actionText?: string
  1889. },
  1890. })
  1891. const instance = new Comp()
  1892. function expectString(s: string) {}
  1893. // instance prop with default should be non-null
  1894. expectString(instance.actionText)
  1895. // public prop on $props should be optional
  1896. // @ts-expect-error
  1897. expectString(instance.$props.actionText)
  1898. // #12122
  1899. defineComponent({
  1900. props: { foo: String },
  1901. render() {
  1902. expectType<{ readonly foo?: string }>(this.$props)
  1903. // @ts-expect-error
  1904. expectType<string>(this.$props)
  1905. },
  1906. })