defineComponent.test-d.tsx 48 KB

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