h.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import {
  2. VNode,
  3. VNodeProps,
  4. createVNode,
  5. VNodeArrayChildren,
  6. Fragment,
  7. isVNode
  8. } from './vnode'
  9. import { Portal, PortalProps } from './components/Portal'
  10. import { Suspense, SuspenseProps } from './components/Suspense'
  11. import { isObject, isArray } from '@vue/shared'
  12. import { RawSlots } from './componentSlots'
  13. import { FunctionalComponent } from './component'
  14. import {
  15. ComponentOptionsWithoutProps,
  16. ComponentOptionsWithArrayProps,
  17. ComponentOptionsWithObjectProps,
  18. ComponentOptions
  19. } from './apiOptions'
  20. import { ExtractPropTypes } from './componentProps'
  21. // `h` is a more user-friendly version of `createVNode` that allows omitting the
  22. // props when possible. It is intended for manually written render functions.
  23. // Compiler-generated code uses `createVNode` because
  24. // 1. it is monomorphic and avoids the extra call overhead
  25. // 2. it allows specifying patchFlags for optimization
  26. /*
  27. // type only
  28. h('div')
  29. // type + props
  30. h('div', {})
  31. // type + omit props + children
  32. // Omit props does NOT support named slots
  33. h('div', []) // array
  34. h('div', 'foo') // text
  35. h('div', h('br')) // vnode
  36. h(Component, () => {}) // default slot
  37. // type + props + children
  38. h('div', {}, []) // array
  39. h('div', {}, 'foo') // text
  40. h('div', {}, h('br')) // vnode
  41. h(Component, {}, () => {}) // default slot
  42. h(Component, {}, {}) // named slots
  43. // named slots without props requires explicit `null` to avoid ambiguity
  44. h(Component, null, {})
  45. **/
  46. type RawProps = VNodeProps & {
  47. // used to differ from a single VNode object as children
  48. _isVNode?: never
  49. // used to differ from Array children
  50. [Symbol.iterator]?: never
  51. }
  52. type RawChildren =
  53. | string
  54. | number
  55. | boolean
  56. | VNode
  57. | VNodeArrayChildren
  58. | (() => any)
  59. // fake constructor type returned from `defineComponent`
  60. interface Constructor<P = any> {
  61. __isFragment?: never
  62. __isPortal?: never
  63. __isSuspense?: never
  64. new (): { $props: P }
  65. }
  66. // The following is a series of overloads for providing props validation of
  67. // manually written render functions.
  68. // element
  69. export function h(type: string, children?: RawChildren): VNode
  70. export function h(
  71. type: string,
  72. props?: RawProps | null,
  73. children?: RawChildren
  74. ): VNode
  75. // fragment
  76. export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode
  77. export function h(
  78. type: typeof Fragment,
  79. props?: RawProps | null,
  80. children?: VNodeArrayChildren
  81. ): VNode
  82. // portal (target prop is required)
  83. export function h(
  84. type: typeof Portal,
  85. props: RawProps & PortalProps,
  86. children: RawChildren
  87. ): VNode
  88. // suspense
  89. export function h(type: typeof Suspense, children?: RawChildren): VNode
  90. export function h(
  91. type: typeof Suspense,
  92. props?: (RawProps & SuspenseProps) | null,
  93. children?: RawChildren | RawSlots
  94. ): VNode
  95. // functional component
  96. export function h(type: FunctionalComponent, children?: RawChildren): VNode
  97. export function h<P>(
  98. type: FunctionalComponent<P>,
  99. props?: (RawProps & P) | ({} extends P ? null : never),
  100. children?: RawChildren | RawSlots
  101. ): VNode
  102. // stateful component
  103. export function h(type: ComponentOptions, children?: RawChildren): VNode
  104. export function h(
  105. type: ComponentOptionsWithoutProps | ComponentOptionsWithArrayProps,
  106. props?: RawProps | null,
  107. children?: RawChildren | RawSlots
  108. ): VNode
  109. export function h<O>(
  110. type: ComponentOptionsWithObjectProps<O>,
  111. props?:
  112. | (RawProps & ExtractPropTypes<O>)
  113. | ({} extends ExtractPropTypes<O> ? null : never),
  114. children?: RawChildren | RawSlots
  115. ): VNode
  116. // fake constructor type returned by `defineComponent` or class component
  117. export function h(type: Constructor, children?: RawChildren): VNode
  118. export function h<P>(
  119. type: Constructor<P>,
  120. props?: (RawProps & P) | ({} extends P ? null : never),
  121. children?: RawChildren | RawSlots
  122. ): VNode
  123. // Actual implementation
  124. export function h(type: any, propsOrChildren?: any, children?: any): VNode {
  125. if (arguments.length === 2) {
  126. if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
  127. // single vnode without props
  128. if (isVNode(propsOrChildren)) {
  129. return createVNode(type, null, [propsOrChildren])
  130. }
  131. // props without children
  132. return createVNode(type, propsOrChildren)
  133. } else {
  134. // omit props
  135. return createVNode(type, null, propsOrChildren)
  136. }
  137. } else {
  138. if (isVNode(children)) {
  139. children = [children]
  140. }
  141. return createVNode(type, propsOrChildren, children)
  142. }
  143. }