defineComponent.test-d.tsx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. import {
  2. describe,
  3. Component,
  4. defineComponent,
  5. PropType,
  6. ref,
  7. reactive,
  8. createApp,
  9. expectError,
  10. expectType,
  11. ComponentPublicInstance,
  12. ComponentOptions,
  13. SetupContext,
  14. h
  15. } from './index'
  16. describe('with object props', () => {
  17. interface ExpectedProps {
  18. a?: number | undefined
  19. b: string
  20. e?: Function
  21. bb: string
  22. bbb: string
  23. cc?: string[] | undefined
  24. dd: { n: 1 }
  25. ee?: () => string
  26. ff?: (a: number, b: string) => { a: boolean }
  27. ccc?: string[] | undefined
  28. ddd: string[]
  29. eee: () => { a: string }
  30. fff: (a: number, b: string) => { a: boolean }
  31. hhh: boolean
  32. ggg: 'foo' | 'bar'
  33. ffff: (a: number, b: string) => { a: boolean }
  34. validated?: string
  35. }
  36. type GT = string & { __brand: unknown }
  37. const MyComponent = defineComponent({
  38. props: {
  39. a: Number,
  40. // required should make property non-void
  41. b: {
  42. type: String,
  43. required: true
  44. },
  45. e: Function,
  46. // default value should infer type and make it non-void
  47. bb: {
  48. default: 'hello'
  49. },
  50. bbb: {
  51. // Note: default function value requires arrow syntax + explicit
  52. // annotation
  53. default: (props: any) => (props.bb as string) || 'foo'
  54. },
  55. // explicit type casting
  56. cc: Array as PropType<string[]>,
  57. // required + type casting
  58. dd: {
  59. type: Object as PropType<{ n: 1 }>,
  60. required: true
  61. },
  62. // return type
  63. ee: Function as PropType<() => string>,
  64. // arguments + object return
  65. ff: Function as PropType<(a: number, b: string) => { a: boolean }>,
  66. // explicit type casting with constructor
  67. ccc: Array as () => string[],
  68. // required + contructor type casting
  69. ddd: {
  70. type: Array as () => string[],
  71. required: true
  72. },
  73. // required + object return
  74. eee: {
  75. type: Function as PropType<() => { a: string }>,
  76. required: true
  77. },
  78. // required + arguments + object return
  79. fff: {
  80. type: Function as PropType<(a: number, b: string) => { a: boolean }>,
  81. required: true
  82. },
  83. hhh: {
  84. type: Boolean,
  85. required: true
  86. },
  87. // default + type casting
  88. ggg: {
  89. type: String as PropType<'foo' | 'bar'>,
  90. default: 'foo'
  91. },
  92. // default + function
  93. ffff: {
  94. type: Function as PropType<(a: number, b: string) => { a: boolean }>,
  95. default: (a: number, b: string) => ({ a: a > +b })
  96. },
  97. validated: {
  98. type: String,
  99. // validator requires explicit annotation
  100. validator: (val: unknown) => val !== ''
  101. }
  102. },
  103. setup(props) {
  104. // type assertion. See https://github.com/SamVerschueren/tsd
  105. expectType<ExpectedProps['a']>(props.a)
  106. expectType<ExpectedProps['b']>(props.b)
  107. expectType<ExpectedProps['e']>(props.e)
  108. expectType<ExpectedProps['bb']>(props.bb)
  109. expectType<ExpectedProps['bbb']>(props.bbb)
  110. expectType<ExpectedProps['cc']>(props.cc)
  111. expectType<ExpectedProps['dd']>(props.dd)
  112. expectType<ExpectedProps['ee']>(props.ee)
  113. expectType<ExpectedProps['ff']>(props.ff)
  114. expectType<ExpectedProps['ccc']>(props.ccc)
  115. expectType<ExpectedProps['ddd']>(props.ddd)
  116. expectType<ExpectedProps['eee']>(props.eee)
  117. expectType<ExpectedProps['fff']>(props.fff)
  118. expectType<ExpectedProps['hhh']>(props.hhh)
  119. expectType<ExpectedProps['ggg']>(props.ggg)
  120. expectType<ExpectedProps['ffff']>(props.ffff)
  121. expectType<ExpectedProps['validated']>(props.validated)
  122. // @ts-expect-error props should be readonly
  123. expectError((props.a = 1))
  124. // setup context
  125. return {
  126. c: ref(1),
  127. d: {
  128. e: ref('hi')
  129. },
  130. f: reactive({
  131. g: ref('hello' as GT)
  132. })
  133. }
  134. },
  135. render() {
  136. const props = this.$props
  137. expectType<ExpectedProps['a']>(props.a)
  138. expectType<ExpectedProps['b']>(props.b)
  139. expectType<ExpectedProps['e']>(props.e)
  140. expectType<ExpectedProps['bb']>(props.bb)
  141. expectType<ExpectedProps['cc']>(props.cc)
  142. expectType<ExpectedProps['dd']>(props.dd)
  143. expectType<ExpectedProps['ee']>(props.ee)
  144. expectType<ExpectedProps['ff']>(props.ff)
  145. expectType<ExpectedProps['ccc']>(props.ccc)
  146. expectType<ExpectedProps['ddd']>(props.ddd)
  147. expectType<ExpectedProps['eee']>(props.eee)
  148. expectType<ExpectedProps['fff']>(props.fff)
  149. expectType<ExpectedProps['hhh']>(props.hhh)
  150. expectType<ExpectedProps['ggg']>(props.ggg)
  151. // @ts-expect-error props should be readonly
  152. expectError((props.a = 1))
  153. // should also expose declared props on `this`
  154. expectType<ExpectedProps['a']>(this.a)
  155. expectType<ExpectedProps['b']>(this.b)
  156. expectType<ExpectedProps['e']>(this.e)
  157. expectType<ExpectedProps['bb']>(this.bb)
  158. expectType<ExpectedProps['cc']>(this.cc)
  159. expectType<ExpectedProps['dd']>(this.dd)
  160. expectType<ExpectedProps['ee']>(this.ee)
  161. expectType<ExpectedProps['ff']>(this.ff)
  162. expectType<ExpectedProps['ccc']>(this.ccc)
  163. expectType<ExpectedProps['ddd']>(this.ddd)
  164. expectType<ExpectedProps['eee']>(this.eee)
  165. expectType<ExpectedProps['fff']>(this.fff)
  166. expectType<ExpectedProps['hhh']>(this.hhh)
  167. expectType<ExpectedProps['ggg']>(this.ggg)
  168. // @ts-expect-error props on `this` should be readonly
  169. expectError((this.a = 1))
  170. // assert setup context unwrapping
  171. expectType<number>(this.c)
  172. expectType<string>(this.d.e.value)
  173. expectType<GT>(this.f.g)
  174. // setup context properties should be mutable
  175. this.c = 2
  176. return null
  177. }
  178. })
  179. expectType<Component>(MyComponent)
  180. // Test TSX
  181. expectType<JSX.Element>(
  182. <MyComponent
  183. a={1}
  184. b="b"
  185. bb="bb"
  186. e={() => {}}
  187. cc={['cc']}
  188. dd={{ n: 1 }}
  189. ee={() => 'ee'}
  190. ccc={['ccc']}
  191. ddd={['ddd']}
  192. eee={() => ({ a: 'eee' })}
  193. fff={(a, b) => ({ a: a > +b })}
  194. hhh={false}
  195. ggg="foo"
  196. // should allow class/style as attrs
  197. class="bar"
  198. style={{ color: 'red' }}
  199. // should allow key
  200. key={'foo'}
  201. // should allow ref
  202. ref={'foo'}
  203. />
  204. )
  205. expectType<Component>(
  206. <MyComponent
  207. b="b"
  208. dd={{ n: 1 }}
  209. ddd={['ddd']}
  210. eee={() => ({ a: 'eee' })}
  211. fff={(a, b) => ({ a: a > +b })}
  212. hhh={false}
  213. />
  214. )
  215. // @ts-expect-error missing required props
  216. expectError(<MyComponent />)
  217. expectError(
  218. // @ts-expect-error wrong prop types
  219. <MyComponent a={'wrong type'} b="foo" dd={{ n: 1 }} ddd={['foo']} />
  220. )
  221. expectError(
  222. // @ts-expect-error wrong prop types
  223. <MyComponent ggg="baz" />
  224. )
  225. // @ts-expect-error
  226. expectError(<MyComponent b="foo" dd={{ n: 'string' }} ddd={['foo']} />)
  227. // `this` should be void inside of prop validators and prop default factories
  228. defineComponent({
  229. props: {
  230. myProp: {
  231. type: Number,
  232. validator(val: unknown): boolean {
  233. // @ts-expect-error
  234. return val !== this.otherProp
  235. },
  236. default(): number {
  237. // @ts-expect-error
  238. return this.otherProp + 1
  239. }
  240. },
  241. otherProp: {
  242. type: Number,
  243. required: true
  244. }
  245. }
  246. })
  247. })
  248. // describe('type inference w/ optional props declaration', () => {
  249. // const MyComponent = defineComponent({
  250. // setup(_props: { msg: string }) {
  251. // return {
  252. // a: 1
  253. // }
  254. // },
  255. // render() {
  256. // expectType<string>(this.$props.msg)
  257. // // props should be readonly
  258. // expectError((this.$props.msg = 'foo'))
  259. // // should not expose on `this`
  260. // expectError(this.msg)
  261. // expectType<number>(this.a)
  262. // return null
  263. // }
  264. // })
  265. // expectType<JSX.Element>(<MyComponent msg="foo" />)
  266. // expectError(<MyComponent />)
  267. // expectError(<MyComponent msg={1} />)
  268. // })
  269. // describe('type inference w/ direct setup function', () => {
  270. // const MyComponent = defineComponent((_props: { msg: string }) => {})
  271. // expectType<JSX.Element>(<MyComponent msg="foo" />)
  272. // expectError(<MyComponent />)
  273. // expectError(<MyComponent msg={1} />)
  274. // })
  275. describe('type inference w/ array props declaration', () => {
  276. const MyComponent = defineComponent({
  277. props: ['a', 'b'],
  278. setup(props) {
  279. // @ts-expect-error props should be readonly
  280. expectError((props.a = 1))
  281. expectType<any>(props.a)
  282. expectType<any>(props.b)
  283. return {
  284. c: 1
  285. }
  286. },
  287. render() {
  288. expectType<any>(this.$props.a)
  289. expectType<any>(this.$props.b)
  290. // @ts-expect-error
  291. expectError((this.$props.a = 1))
  292. expectType<any>(this.a)
  293. expectType<any>(this.b)
  294. expectType<number>(this.c)
  295. }
  296. })
  297. expectType<JSX.Element>(<MyComponent a={[1, 2]} b="b" />)
  298. // @ts-expect-error
  299. expectError(<MyComponent other="other" />)
  300. })
  301. describe('type inference w/ options API', () => {
  302. defineComponent({
  303. props: { a: Number },
  304. setup() {
  305. return {
  306. b: 123
  307. }
  308. },
  309. data() {
  310. // Limitation: we cannot expose the return result of setup() on `this`
  311. // here in data() - somehow that would mess up the inference
  312. expectType<number | undefined>(this.a)
  313. return {
  314. c: this.a || 123
  315. }
  316. },
  317. computed: {
  318. d(): number {
  319. expectType<number>(this.b)
  320. return this.b + 1
  321. },
  322. e: {
  323. get(): number {
  324. expectType<number>(this.b)
  325. expectType<number>(this.d)
  326. return this.b + this.d
  327. },
  328. set(v: number) {
  329. expectType<number>(this.b)
  330. expectType<number>(this.d)
  331. expectType<number>(v)
  332. }
  333. }
  334. },
  335. watch: {
  336. a() {
  337. expectType<number>(this.b)
  338. this.b + 1
  339. }
  340. },
  341. created() {
  342. // props
  343. expectType<number | undefined>(this.a)
  344. // returned from setup()
  345. expectType<number>(this.b)
  346. // returned from data()
  347. expectType<number>(this.c)
  348. // computed
  349. expectType<number>(this.d)
  350. // computed get/set
  351. expectType<number>(this.e)
  352. },
  353. methods: {
  354. doSomething() {
  355. // props
  356. expectType<number | undefined>(this.a)
  357. // returned from setup()
  358. expectType<number>(this.b)
  359. // returned from data()
  360. expectType<number>(this.c)
  361. // computed
  362. expectType<number>(this.d)
  363. // computed get/set
  364. expectType<number>(this.e)
  365. },
  366. returnSomething() {
  367. return this.a
  368. }
  369. },
  370. render() {
  371. // props
  372. expectType<number | undefined>(this.a)
  373. // returned from setup()
  374. expectType<number>(this.b)
  375. // returned from data()
  376. expectType<number>(this.c)
  377. // computed
  378. expectType<number>(this.d)
  379. // computed get/set
  380. expectType<number>(this.e)
  381. // method
  382. expectType<() => number | undefined>(this.returnSomething)
  383. }
  384. })
  385. })
  386. describe('with mixins', () => {
  387. const MixinA = defineComponent({
  388. props: {
  389. aP1: {
  390. type: String,
  391. default: 'aP1'
  392. },
  393. aP2: Boolean
  394. },
  395. data() {
  396. return {
  397. a: 1
  398. }
  399. }
  400. })
  401. const MixinB = defineComponent({
  402. props: ['bP1', 'bP2'],
  403. data() {
  404. return {
  405. b: 2
  406. }
  407. }
  408. })
  409. const MixinC = defineComponent({
  410. data() {
  411. return {
  412. c: 3
  413. }
  414. }
  415. })
  416. const MixinD = defineComponent({
  417. mixins: [MixinA],
  418. data() {
  419. return {
  420. d: 4
  421. }
  422. },
  423. computed: {
  424. dC1(): number {
  425. return this.d + this.a
  426. },
  427. dC2(): string {
  428. return this.aP1 + 'dC2'
  429. }
  430. }
  431. })
  432. const MyComponent = defineComponent({
  433. mixins: [MixinA, MixinB, MixinC, MixinD],
  434. props: {
  435. // required should make property non-void
  436. z: {
  437. type: String,
  438. required: true
  439. }
  440. },
  441. render() {
  442. const props = this.$props
  443. // props
  444. expectType<string>(props.aP1)
  445. expectType<boolean | undefined>(props.aP2)
  446. expectType<any>(props.bP1)
  447. expectType<any>(props.bP2)
  448. expectType<string>(props.z)
  449. const data = this.$data
  450. expectType<number>(data.a)
  451. expectType<number>(data.b)
  452. expectType<number>(data.c)
  453. expectType<number>(data.d)
  454. // should also expose declared props on `this`
  455. expectType<number>(this.a)
  456. expectType<string>(this.aP1)
  457. expectType<boolean | undefined>(this.aP2)
  458. expectType<number>(this.b)
  459. expectType<any>(this.bP1)
  460. expectType<number>(this.c)
  461. expectType<number>(this.d)
  462. expectType<number>(this.dC1)
  463. expectType<string>(this.dC2)
  464. // props should be readonly
  465. // @ts-expect-error
  466. expectError((this.aP1 = 'new'))
  467. // @ts-expect-error
  468. expectError((this.z = 1))
  469. // props on `this` should be readonly
  470. // @ts-expect-error
  471. expectError((this.bP1 = 1))
  472. // string value can not assigned to number type value
  473. // @ts-expect-error
  474. expectError((this.c = '1'))
  475. // setup context properties should be mutable
  476. this.d = 5
  477. return null
  478. }
  479. })
  480. // Test TSX
  481. expectType<JSX.Element>(
  482. <MyComponent aP1={'aP'} aP2 bP1={1} bP2={[1, 2]} z={'z'} />
  483. )
  484. // missing required props
  485. // @ts-expect-error
  486. expectError(<MyComponent />)
  487. // wrong prop types
  488. // @ts-expect-error
  489. expectError(<MyComponent aP1="ap" aP2={'wrong type'} bP1="b" z={'z'} />)
  490. // @ts-expect-error
  491. expectError(<MyComponent aP1={1} bP2={[1]} />)
  492. })
  493. describe('with extends', () => {
  494. const Base = defineComponent({
  495. props: {
  496. aP1: Boolean,
  497. aP2: {
  498. type: Number,
  499. default: 2
  500. }
  501. },
  502. data() {
  503. return {
  504. a: 1
  505. }
  506. },
  507. computed: {
  508. c(): number {
  509. return this.aP2 + this.a
  510. }
  511. }
  512. })
  513. const MyComponent = defineComponent({
  514. extends: Base,
  515. props: {
  516. // required should make property non-void
  517. z: {
  518. type: String,
  519. required: true
  520. }
  521. },
  522. render() {
  523. const props = this.$props
  524. // props
  525. expectType<boolean | undefined>(props.aP1)
  526. expectType<number>(props.aP2)
  527. expectType<string>(props.z)
  528. const data = this.$data
  529. expectType<number>(data.a)
  530. // should also expose declared props on `this`
  531. expectType<number>(this.a)
  532. expectType<boolean | undefined>(this.aP1)
  533. expectType<number>(this.aP2)
  534. // setup context properties should be mutable
  535. this.a = 5
  536. return null
  537. }
  538. })
  539. // Test TSX
  540. expectType<JSX.Element>(<MyComponent aP2={3} aP1 z={'z'} />)
  541. // missing required props
  542. // @ts-expect-error
  543. expectError(<MyComponent />)
  544. // wrong prop types
  545. // @ts-expect-error
  546. expectError(<MyComponent aP2={'wrong type'} z={'z'} />)
  547. // @ts-expect-error
  548. expectError(<MyComponent aP1={3} />)
  549. })
  550. describe('extends with mixins', () => {
  551. const Mixin = defineComponent({
  552. props: {
  553. mP1: {
  554. type: String,
  555. default: 'mP1'
  556. },
  557. mP2: Boolean,
  558. mP3: {
  559. type: Boolean,
  560. required: true
  561. }
  562. },
  563. data() {
  564. return {
  565. a: 1
  566. }
  567. }
  568. })
  569. const Base = defineComponent({
  570. props: {
  571. p1: Boolean,
  572. p2: {
  573. type: Number,
  574. default: 2
  575. },
  576. p3: {
  577. type: Boolean,
  578. required: true
  579. }
  580. },
  581. data() {
  582. return {
  583. b: 2
  584. }
  585. },
  586. computed: {
  587. c(): number {
  588. return this.p2 + this.b
  589. }
  590. }
  591. })
  592. const MyComponent = defineComponent({
  593. extends: Base,
  594. mixins: [Mixin],
  595. props: {
  596. // required should make property non-void
  597. z: {
  598. type: String,
  599. required: true
  600. }
  601. },
  602. render() {
  603. const props = this.$props
  604. // props
  605. expectType<boolean | undefined>(props.p1)
  606. expectType<number>(props.p2)
  607. expectType<string>(props.z)
  608. expectType<string>(props.mP1)
  609. expectType<boolean | undefined>(props.mP2)
  610. const data = this.$data
  611. expectType<number>(data.a)
  612. expectType<number>(data.b)
  613. // should also expose declared props on `this`
  614. expectType<number>(this.a)
  615. expectType<number>(this.b)
  616. expectType<boolean | undefined>(this.p1)
  617. expectType<number>(this.p2)
  618. expectType<string>(this.mP1)
  619. expectType<boolean | undefined>(this.mP2)
  620. // setup context properties should be mutable
  621. this.a = 5
  622. return null
  623. }
  624. })
  625. // Test TSX
  626. expectType<JSX.Element>(<MyComponent mP1="p1" mP2 mP3 p1 p2={1} p3 z={'z'} />)
  627. // mP1, mP2, p1, and p2 have default value. these are not required
  628. expectType<JSX.Element>(<MyComponent mP3 p3 z={'z'} />)
  629. // missing required props
  630. // @ts-expect-error
  631. expectError(<MyComponent mP3 p3 /* z='z' */ />)
  632. // missing required props from mixin
  633. // @ts-expect-error
  634. expectError(<MyComponent /* mP3 */ p3 z="z" />)
  635. // missing required props from extends
  636. // @ts-expect-error
  637. expectError(<MyComponent mP3 /* p3 */ z="z" />)
  638. // wrong prop types
  639. // @ts-expect-error
  640. expectError(<MyComponent p2={'wrong type'} z={'z'} />)
  641. // @ts-expect-error
  642. expectError(<MyComponent mP1={3} />)
  643. })
  644. describe('compatibility w/ createApp', () => {
  645. const comp = defineComponent({})
  646. createApp(comp).mount('#hello')
  647. const comp2 = defineComponent({
  648. props: { foo: String }
  649. })
  650. createApp(comp2).mount('#hello')
  651. const comp3 = defineComponent({
  652. setup() {
  653. return {
  654. a: 1
  655. }
  656. }
  657. })
  658. createApp(comp3).mount('#hello')
  659. })
  660. describe('defineComponent', () => {
  661. test('should accept components defined with defineComponent', () => {
  662. const comp = defineComponent({})
  663. defineComponent({
  664. components: { comp }
  665. })
  666. })
  667. test('should accept class components with receiving constructor arguments', () => {
  668. class Comp {
  669. static __vccOpts = {}
  670. constructor(_props: { foo: string }) {}
  671. }
  672. defineComponent({
  673. components: { Comp }
  674. })
  675. })
  676. })
  677. describe('emits', () => {
  678. // Note: for TSX inference, ideally we want to map emits to onXXX props,
  679. // but that requires type-level string constant concatenation as suggested in
  680. // https://github.com/Microsoft/TypeScript/issues/12754
  681. // The workaround for TSX users is instead of using emits, declare onXXX props
  682. // and call them instead. Since `v-on:click` compiles to an `onClick` prop,
  683. // this would also support other users consuming the component in templates
  684. // with `v-on` listeners.
  685. // with object emits
  686. defineComponent({
  687. emits: {
  688. click: (n: number) => typeof n === 'number',
  689. input: (b: string) => b.length > 1
  690. },
  691. setup(props, { emit }) {
  692. emit('click', 1)
  693. emit('input', 'foo')
  694. // @ts-expect-error
  695. expectError(emit('nope'))
  696. // @ts-expect-error
  697. expectError(emit('click'))
  698. // @ts-expect-error
  699. expectError(emit('click', 'foo'))
  700. // @ts-expect-error
  701. expectError(emit('input'))
  702. // @ts-expect-error
  703. expectError(emit('input', 1))
  704. },
  705. created() {
  706. this.$emit('click', 1)
  707. this.$emit('input', 'foo')
  708. // @ts-expect-error
  709. expectError(this.$emit('nope'))
  710. // @ts-expect-error
  711. expectError(this.$emit('click'))
  712. // @ts-expect-error
  713. expectError(this.$emit('click', 'foo'))
  714. // @ts-expect-error
  715. expectError(this.$emit('input'))
  716. // @ts-expect-error
  717. expectError(this.$emit('input', 1))
  718. }
  719. })
  720. // with array emits
  721. defineComponent({
  722. emits: ['foo', 'bar'],
  723. setup(props, { emit }) {
  724. emit('foo')
  725. emit('foo', 123)
  726. emit('bar')
  727. // @ts-expect-error
  728. expectError(emit('nope'))
  729. },
  730. created() {
  731. this.$emit('foo')
  732. this.$emit('foo', 123)
  733. this.$emit('bar')
  734. // @ts-expect-error
  735. expectError(this.$emit('nope'))
  736. }
  737. })
  738. // without emits
  739. defineComponent({
  740. setup(props, { emit }) {
  741. emit('test', 1)
  742. emit('test')
  743. }
  744. })
  745. // emit should be valid when ComponentPublicInstance is used.
  746. const instance = {} as ComponentPublicInstance
  747. instance.$emit('test', 1)
  748. instance.$emit('test')
  749. // `this` should be void inside of emits validators
  750. defineComponent({
  751. props: ['bar'],
  752. emits: {
  753. foo(): boolean {
  754. // @ts-expect-error
  755. return this.bar === 3
  756. }
  757. }
  758. })
  759. })
  760. describe('componentOptions setup should be `SetupContext`', () => {
  761. expect<ComponentOptions['setup']>({} as (
  762. props: Record<string, any>,
  763. ctx: SetupContext
  764. ) => any)
  765. })
  766. describe('extract instance type', () => {
  767. const Base = defineComponent({
  768. props: {
  769. baseA: {
  770. type: Number,
  771. default: 1
  772. }
  773. }
  774. })
  775. const MixinA = defineComponent({
  776. props: {
  777. mA: {
  778. type: String,
  779. default: ''
  780. }
  781. }
  782. })
  783. const CompA = defineComponent({
  784. extends: Base,
  785. mixins: [MixinA],
  786. props: {
  787. a: {
  788. type: Boolean,
  789. default: false
  790. },
  791. b: {
  792. type: String,
  793. required: true
  794. },
  795. c: Number
  796. }
  797. })
  798. const compA = {} as InstanceType<typeof CompA>
  799. expectType<boolean>(compA.a)
  800. expectType<string>(compA.b)
  801. expectType<number | undefined>(compA.c)
  802. // mixins
  803. expectType<string>(compA.mA)
  804. // extends
  805. expectType<number>(compA.baseA)
  806. // @ts-expect-error
  807. expectError((compA.a = true))
  808. // @ts-expect-error
  809. expectError((compA.b = 'foo'))
  810. // @ts-expect-error
  811. expectError((compA.c = 1))
  812. // @ts-expect-error
  813. expectError((compA.mA = 'foo'))
  814. // @ts-expect-error
  815. expectError((compA.baseA = 1))
  816. })
  817. describe('async setup', () => {
  818. type GT = string & { __brand: unknown }
  819. const Comp = defineComponent({
  820. async setup() {
  821. // setup context
  822. return {
  823. a: ref(1),
  824. b: {
  825. c: ref('hi')
  826. },
  827. d: reactive({
  828. e: ref('hello' as GT)
  829. })
  830. }
  831. },
  832. render() {
  833. // assert setup context unwrapping
  834. expectType<number>(this.a)
  835. expectType<string>(this.b.c.value)
  836. expectType<GT>(this.d.e)
  837. // setup context properties should be mutable
  838. this.a = 2
  839. }
  840. })
  841. const vm = {} as InstanceType<typeof Comp>
  842. // assert setup context unwrapping
  843. expectType<number>(vm.a)
  844. expectType<string>(vm.b.c.value)
  845. expectType<GT>(vm.d.e)
  846. // setup context properties should be mutable
  847. vm.a = 2
  848. })
  849. // check if defineComponent can be exported
  850. export default {
  851. // function components
  852. a: defineComponent(_ => h('div')),
  853. // no props
  854. b: defineComponent({
  855. data() {
  856. return {}
  857. }
  858. }),
  859. c: defineComponent({
  860. props: ['a']
  861. }),
  862. d: defineComponent({
  863. props: {
  864. a: Number
  865. }
  866. })
  867. }