h.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import {
  2. type Comment,
  3. type Fragment,
  4. type Text,
  5. type VNode,
  6. type VNodeArrayChildren,
  7. type VNodeProps,
  8. createVNode,
  9. isVNode,
  10. setBlockTracking,
  11. } from './vnode'
  12. import type { Teleport, TeleportProps } from './components/Teleport'
  13. import type { Suspense, SuspenseProps } from './components/Suspense'
  14. import { type IfAny, isArray, isObject } from '@vue/shared'
  15. import type { RawSlots } from './componentSlots'
  16. import type {
  17. Component,
  18. ComponentOptions,
  19. ConcreteComponent,
  20. FunctionalComponent,
  21. } from './component'
  22. import type { EmitsOptions } from './componentEmits'
  23. import type { DefineComponent } from './apiDefineComponent'
  24. // `h` is a more user-friendly version of `createVNode` that allows omitting the
  25. // props when possible. It is intended for manually written render functions.
  26. // Compiler-generated code uses `createVNode` because
  27. // 1. it is monomorphic and avoids the extra call overhead
  28. // 2. it allows specifying patchFlags for optimization
  29. /*
  30. // type only
  31. h('div')
  32. // type + props
  33. h('div', {})
  34. // type + omit props + children
  35. // Omit props does NOT support named slots
  36. h('div', []) // array
  37. h('div', 'foo') // text
  38. h('div', h('br')) // vnode
  39. h(Component, () => {}) // default slot
  40. // type + props + children
  41. h('div', {}, []) // array
  42. h('div', {}, 'foo') // text
  43. h('div', {}, h('br')) // vnode
  44. h(Component, {}, () => {}) // default slot
  45. h(Component, {}, {}) // named slots
  46. // named slots without props requires explicit `null` to avoid ambiguity
  47. h(Component, null, {})
  48. **/
  49. type RawProps = VNodeProps & {
  50. // used to differ from a single VNode object as children
  51. __v_isVNode?: never
  52. // used to differ from Array children
  53. [Symbol.iterator]?: never
  54. } & Record<string, any>
  55. type RawChildren =
  56. | string
  57. | number
  58. | boolean
  59. | VNode
  60. | VNodeArrayChildren
  61. | (() => any)
  62. // fake constructor type returned from `defineComponent`
  63. interface Constructor<P = any> {
  64. __isFragment?: never
  65. __isTeleport?: never
  66. __isSuspense?: never
  67. new (...args: any[]): { $props: P }
  68. }
  69. type HTMLElementEventHandler = {
  70. [K in keyof HTMLElementEventMap as `on${Capitalize<K>}`]?: (
  71. ev: HTMLElementEventMap[K],
  72. ) => any
  73. }
  74. // The following is a series of overloads for providing props validation of
  75. // manually written render functions.
  76. // element
  77. export function h<K extends keyof HTMLElementTagNameMap>(
  78. type: K,
  79. children?: RawChildren,
  80. ): VNode
  81. export function h<K extends keyof HTMLElementTagNameMap>(
  82. type: K,
  83. props?: (RawProps & HTMLElementEventHandler) | null,
  84. children?: RawChildren | RawSlots,
  85. ): VNode
  86. // custom element
  87. export function h(type: string, children?: RawChildren): VNode
  88. export function h(
  89. type: string,
  90. props?: RawProps | null,
  91. children?: RawChildren | RawSlots,
  92. ): VNode
  93. // text/comment
  94. export function h(
  95. type: typeof Text | typeof Comment,
  96. children?: string | number | boolean,
  97. ): VNode
  98. export function h(
  99. type: typeof Text | typeof Comment,
  100. props?: null,
  101. children?: string | number | boolean,
  102. ): VNode
  103. // fragment
  104. export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode
  105. export function h(
  106. type: typeof Fragment,
  107. props?: RawProps | null,
  108. children?: VNodeArrayChildren,
  109. ): VNode
  110. // teleport (target prop is required)
  111. export function h(
  112. type: typeof Teleport,
  113. props: RawProps & TeleportProps,
  114. children: RawChildren | RawSlots,
  115. ): VNode
  116. // suspense
  117. export function h(type: typeof Suspense, children?: RawChildren): VNode
  118. export function h(
  119. type: typeof Suspense,
  120. props?: (RawProps & SuspenseProps) | null,
  121. children?: RawChildren | RawSlots,
  122. ): VNode
  123. // functional component
  124. export function h<
  125. P,
  126. E extends EmitsOptions = {},
  127. S extends Record<string, any> = any,
  128. >(
  129. type: FunctionalComponent<P, any, S, any>,
  130. props?: (RawProps & P) | ({} extends P ? null : never),
  131. children?: RawChildren | IfAny<S, RawSlots, S>,
  132. ): VNode
  133. // catch-all for generic component types
  134. export function h(type: Component, children?: RawChildren): VNode
  135. // concrete component
  136. export function h<P>(
  137. type: ConcreteComponent | string,
  138. children?: RawChildren,
  139. ): VNode
  140. export function h<P>(
  141. type: ConcreteComponent<P> | string,
  142. props?: (RawProps & P) | ({} extends P ? null : never),
  143. children?: RawChildren,
  144. ): VNode
  145. // component without props
  146. export function h<P>(
  147. type: Component<P>,
  148. props?: (RawProps & P) | null,
  149. children?: RawChildren | RawSlots,
  150. ): VNode
  151. // exclude `defineComponent` constructors
  152. export function h<P>(
  153. type: ComponentOptions<P>,
  154. props?: (RawProps & P) | ({} extends P ? null : never),
  155. children?: RawChildren | RawSlots,
  156. ): VNode
  157. // fake constructor type returned by `defineComponent` or class component
  158. export function h(type: Constructor, children?: RawChildren): VNode
  159. export function h<P>(
  160. type: Constructor<P>,
  161. props?: (RawProps & P) | ({} extends P ? null : never),
  162. children?: RawChildren | RawSlots,
  163. ): VNode
  164. // fake constructor type returned by `defineComponent`
  165. export function h(type: DefineComponent, children?: RawChildren): VNode
  166. export function h<P>(
  167. type: DefineComponent<P>,
  168. props?: (RawProps & P) | ({} extends P ? null : never),
  169. children?: RawChildren | RawSlots,
  170. ): VNode
  171. // catch all types
  172. export function h(type: string | Component, children?: RawChildren): VNode
  173. export function h<P>(
  174. type: string | Component<P>,
  175. props?: (RawProps & P) | ({} extends P ? null : never),
  176. children?: RawChildren | RawSlots,
  177. ): VNode
  178. // Actual implementation
  179. export function h(type: any, propsOrChildren?: any, children?: any): VNode {
  180. try {
  181. // #6913 disable tracking block in h function
  182. setBlockTracking(-1)
  183. const l = arguments.length
  184. if (l === 2) {
  185. if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
  186. // single vnode without props
  187. if (isVNode(propsOrChildren)) {
  188. return createVNode(type, null, [propsOrChildren])
  189. }
  190. // props without children
  191. return createVNode(type, propsOrChildren)
  192. } else {
  193. // omit props
  194. return createVNode(type, null, propsOrChildren)
  195. }
  196. } else {
  197. if (l > 3) {
  198. children = Array.prototype.slice.call(arguments, 2)
  199. } else if (l === 3 && isVNode(children)) {
  200. children = [children]
  201. }
  202. return createVNode(type, propsOrChildren, children)
  203. }
  204. } finally {
  205. setBlockTracking(1)
  206. }
  207. }