apiCreateComponent.spec.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import { createComponent } from '../src/component'
  2. import { ref } from '@vue/reactivity'
  3. import { PropType } from '../src/componentProps'
  4. import { h } from '../src/h'
  5. // mock React just for TSX testing purposes
  6. const React = {
  7. createElement: () => {}
  8. }
  9. test('createComponent type inference', () => {
  10. const MyComponent = createComponent({
  11. props: {
  12. a: Number,
  13. // required should make property non-void
  14. b: {
  15. type: String,
  16. required: true
  17. },
  18. // default value should infer type and make it non-void
  19. bb: {
  20. default: 'hello'
  21. },
  22. // explicit type casting
  23. cc: (Array as any) as PropType<string[]>,
  24. // required + type casting
  25. dd: {
  26. type: (Array as any) as PropType<string[]>,
  27. required: true
  28. }
  29. } as const, // required to narrow for conditional check
  30. setup(props) {
  31. props.a && props.a * 2
  32. props.b.slice()
  33. props.bb.slice()
  34. props.cc && props.cc.push('hoo')
  35. props.dd.push('dd')
  36. return {
  37. c: ref(1),
  38. d: {
  39. e: ref('hi')
  40. }
  41. }
  42. },
  43. render() {
  44. const props = this.$props
  45. props.a && props.a * 2
  46. props.b.slice()
  47. props.bb.slice()
  48. props.cc && props.cc.push('hoo')
  49. props.dd.push('dd')
  50. this.a && this.a * 2
  51. this.b.slice()
  52. this.bb.slice()
  53. this.c * 2
  54. this.d.e.slice()
  55. this.cc && this.cc.push('hoo')
  56. this.dd.push('dd')
  57. return h('div', this.bb)
  58. }
  59. })
  60. // test TSX props inference
  61. ;(<MyComponent a={1} b="foo" dd={['foo']}/>)
  62. })
  63. test('type inference w/ optional props declaration', () => {
  64. const Comp = createComponent({
  65. setup(props: { msg: string }) {
  66. props.msg
  67. return {
  68. a: 1
  69. }
  70. },
  71. render() {
  72. this.$props.msg
  73. this.msg
  74. this.a * 2
  75. return h('div', this.msg)
  76. }
  77. })
  78. ;(<Comp msg="hello"/>)
  79. })
  80. test('type inference w/ direct setup function', () => {
  81. const Comp = createComponent((props: { msg: string }) => {
  82. return () => <div>{props.msg}</div>
  83. })
  84. ;(<Comp msg="hello"/>)
  85. })
  86. test('type inference w/ array props declaration', () => {
  87. const Comp = createComponent({
  88. props: ['a', 'b'],
  89. setup(props) {
  90. props.a
  91. props.b
  92. return {
  93. c: 1
  94. }
  95. },
  96. render() {
  97. this.$props.a
  98. this.$props.b
  99. this.a
  100. this.b
  101. this.c
  102. }
  103. })
  104. ;(<Comp a={1} b={2}/>)
  105. })
  106. test('with legacy options', () => {
  107. createComponent({
  108. props: { a: Number },
  109. setup() {
  110. return {
  111. b: 123
  112. }
  113. },
  114. data() {
  115. // Limitation: we cannot expose the return result of setup() on `this`
  116. // here in data() - somehow that would mess up the inference
  117. return {
  118. c: this.a || 123
  119. }
  120. },
  121. computed: {
  122. d(): number {
  123. return this.b + 1
  124. }
  125. },
  126. watch: {
  127. a() {
  128. this.b + 1
  129. }
  130. },
  131. created() {
  132. this.a && this.a * 2
  133. this.b * 2
  134. this.c * 2
  135. this.d * 2
  136. },
  137. methods: {
  138. doSomething() {
  139. this.a && this.a * 2
  140. this.b * 2
  141. this.c * 2
  142. this.d * 2
  143. return (this.a || 0) + this.b + this.c + this.d
  144. }
  145. },
  146. render() {
  147. this.a && this.a * 2
  148. this.b * 2
  149. this.c * 2
  150. this.d * 2
  151. return h('div', (this.a || 0) + this.b + this.c + this.d)
  152. }
  153. })
  154. })