h.ts 4.1 KB

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