]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(types): widen `Component` type to include consutructor types
authorEvan You <yyx990803@gmail.com>
Wed, 19 Aug 2020 20:11:29 +0000 (16:11 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 19 Aug 2020 20:19:25 +0000 (16:19 -0400)
returned from `defineComponent`

ref: https://github.com/vuejs/vue-router-next/pull/421
also close #1880

Previous `Component` type is now exported as `ConcreteComponent`.

This introduces a minor breaking change when calling `h(comp, { ... })`
will now fail if `comp` is a of generic `Component` type, since it does
not specify what props it expects.

21 files changed:
packages/runtime-core/__tests__/components/Suspense.spec.ts
packages/runtime-core/src/apiAsyncComponent.ts
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-core/src/apiDefineComponent.ts
packages/runtime-core/src/apiLifecycle.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentEmits.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentPublicInstance.ts [moved from packages/runtime-core/src/componentProxy.ts with 99% similarity]
packages/runtime-core/src/components/KeepAlive.ts
packages/runtime-core/src/directives.ts
packages/runtime-core/src/h.ts
packages/runtime-core/src/helpers/resolveAssets.ts
packages/runtime-core/src/hmr.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/renderer.ts
packages/runtime-core/src/vnode.ts
packages/runtime-core/src/warning.ts
test-dts/defineComponent.test-d.tsx
test-dts/h.test-d.ts

index afe8873a32615ff617fa692326d6d296a0365370..ffc9f903ffac6a923ed0b24b5971c1e991effe87 100644 (file)
@@ -11,8 +11,7 @@ import {
   watch,
   watchEffect,
   onUnmounted,
-  onErrorCaptured,
-  Component
+  onErrorCaptured
 } from '@vue/runtime-test'
 
 describe('Suspense', () => {
@@ -31,7 +30,7 @@ describe('Suspense', () => {
       setup(props: any, { slots }: any) {
         const p = new Promise(resolve => {
           setTimeout(() => {
-            resolve(() => h<Component>(comp, props, slots))
+            resolve(() => h(comp, props, slots))
           }, delay)
         })
         // in Node 12, due to timer/nextTick mechanism change, we have to wait
index 7f65f3b47b2540bd03adaa72552848cfee23ef93..3f668a4624287a8b22a7798357b6ba93784a258b 100644 (file)
@@ -1,21 +1,19 @@
 import {
-  PublicAPIComponent,
   Component,
+  ConcreteComponent,
   currentInstance,
   ComponentInternalInstance,
   isInSSRComponentSetup
 } from './component'
 import { isFunction, isObject } from '@vue/shared'
-import { ComponentPublicInstance } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstance'
 import { createVNode } from './vnode'
 import { defineComponent } from './apiDefineComponent'
 import { warn } from './warning'
 import { ref } from '@vue/reactivity'
 import { handleError, ErrorCodes } from './errorHandling'
 
-export type AsyncComponentResolveResult<T = PublicAPIComponent> =
-  | T
-  | { default: T } // es modules
+export type AsyncComponentResolveResult<T = Component> = T | { default: T } // es modules
 
 export type AsyncComponentLoader<T = any> = () => Promise<
   AsyncComponentResolveResult<T>
@@ -23,8 +21,8 @@ export type AsyncComponentLoader<T = any> = () => Promise<
 
 export interface AsyncComponentOptions<T = any> {
   loader: AsyncComponentLoader<T>
-  loadingComponent?: PublicAPIComponent
-  errorComponent?: PublicAPIComponent
+  loadingComponent?: Component
+  errorComponent?: Component
   delay?: number
   timeout?: number
   suspensible?: boolean
@@ -37,7 +35,7 @@ export interface AsyncComponentOptions<T = any> {
 }
 
 export function defineAsyncComponent<
-  T extends PublicAPIComponent = { new (): ComponentPublicInstance }
+  T extends Component = { new (): ComponentPublicInstance }
 >(source: AsyncComponentLoader<T> | AsyncComponentOptions<T>): T {
   if (isFunction(source)) {
     source = { loader: source }
@@ -53,8 +51,8 @@ export function defineAsyncComponent<
     onError: userOnError
   } = source
 
-  let pendingRequest: Promise<Component> | null = null
-  let resolvedComp: Component | undefined
+  let pendingRequest: Promise<ConcreteComponent> | null = null
+  let resolvedComp: ConcreteComponent | undefined
 
   let retries = 0
   const retry = () => {
@@ -63,8 +61,8 @@ export function defineAsyncComponent<
     return load()
   }
 
-  const load = (): Promise<Component> => {
-    let thisRequest: Promise<Component>
+  const load = (): Promise<ConcreteComponent> => {
+    let thisRequest: Promise<ConcreteComponent>
     return (
       pendingRequest ||
       (thisRequest = pendingRequest = loader()
@@ -135,7 +133,9 @@ export function defineAsyncComponent<
             onError(err)
             return () =>
               errorComponent
-                ? createVNode(errorComponent as Component, { error: err })
+                ? createVNode(errorComponent as ConcreteComponent, {
+                    error: err
+                  })
                 : null
           })
       }
@@ -175,11 +175,11 @@ export function defineAsyncComponent<
         if (loaded.value && resolvedComp) {
           return createInnerComp(resolvedComp, instance)
         } else if (error.value && errorComponent) {
-          return createVNode(errorComponent as Component, {
+          return createVNode(errorComponent as ConcreteComponent, {
             error: error.value
           })
         } else if (loadingComponent && !delayed.value) {
-          return createVNode(loadingComponent as Component)
+          return createVNode(loadingComponent as ConcreteComponent)
         }
       }
     }
@@ -187,7 +187,7 @@ export function defineAsyncComponent<
 }
 
 function createInnerComp(
-  comp: Component,
+  comp: ConcreteComponent,
   { vnode: { props, children } }: ComponentInternalInstance
 ) {
   return createVNode(comp, props, children)
index 61710a5c89598afba80647976ce5b94d619a08ef..a75f5d32ece38b8bf322cfb3b9d81277aba272af 100644 (file)
@@ -1,11 +1,11 @@
 import {
-  Component,
+  ConcreteComponent,
   Data,
   validateComponentName,
-  PublicAPIComponent
+  Component
 } from './component'
 import { ComponentOptions } from './componentOptions'
-import { ComponentPublicInstance } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstance'
 import { Directive, validateDirectiveName } from './directives'
 import { RootRenderFunction } from './renderer'
 import { InjectionKey } from './apiInject'
@@ -21,8 +21,8 @@ export interface App<HostElement = any> {
   config: AppConfig
   use(plugin: Plugin, ...options: any[]): this
   mixin(mixin: ComponentOptions): this
-  component(name: string): PublicAPIComponent | undefined
-  component(name: string, component: PublicAPIComponent): this
+  component(name: string): Component | undefined
+  component(name: string, component: Component): this
   directive(name: string): Directive | undefined
   directive(name: string, directive: Directive): this
   mount(
@@ -33,7 +33,7 @@ export interface App<HostElement = any> {
   provide<T>(key: InjectionKey<T> | string, value: T): this
 
   // internal, but we need to expose these for the server-renderer and devtools
-  _component: Component
+  _component: ConcreteComponent
   _props: Data | null
   _container: HostElement | null
   _context: AppContext
@@ -70,7 +70,7 @@ export interface AppContext {
   app: App // for devtools
   config: AppConfig
   mixins: ComponentOptions[]
-  components: Record<string, PublicAPIComponent>
+  components: Record<string, Component>
   directives: Record<string, Directive>
   provides: Record<string | symbol, any>
   reload?: () => void // HMR only
@@ -104,7 +104,7 @@ export function createAppContext(): AppContext {
 }
 
 export type CreateAppFunction<HostElement> = (
-  rootComponent: PublicAPIComponent,
+  rootComponent: Component,
   rootProps?: Data | null
 ) => App<HostElement>
 
@@ -124,7 +124,7 @@ export function createAppAPI<HostElement>(
     let isMounted = false
 
     const app: App = (context.app = {
-      _component: rootComponent as Component,
+      _component: rootComponent as ConcreteComponent,
       _props: rootProps,
       _container: null,
       _context: context,
@@ -177,7 +177,7 @@ export function createAppAPI<HostElement>(
         return app
       },
 
-      component(name: string, component?: PublicAPIComponent): any {
+      component(name: string, component?: Component): any {
         if (__DEV__) {
           validateComponentName(name, context.config)
         }
@@ -208,7 +208,10 @@ export function createAppAPI<HostElement>(
 
       mount(rootContainer: HostElement, isHydrate?: boolean): any {
         if (!isMounted) {
-          const vnode = createVNode(rootComponent as Component, rootProps)
+          const vnode = createVNode(
+            rootComponent as ConcreteComponent,
+            rootProps
+          )
           // store app context on the root VNode.
           // this will be set on the root instance on initial mount.
           vnode.appContext = context
index b85e3b3b7326fd6926d795c85f32067e16098bdb..4a100d8f6c58eb3dd4ef4ec9c15fedc04c3cc93e 100644 (file)
@@ -16,7 +16,7 @@ import {
 import {
   CreateComponentPublicInstance,
   ComponentPublicInstanceConstructor
-} from './componentProxy'
+} from './componentPublicInstance'
 import { ExtractPropTypes, ComponentPropsOptions } from './componentProps'
 import { EmitsOptions } from './componentEmits'
 import { isFunction } from '@vue/shared'
@@ -205,7 +205,5 @@ export function defineComponent<
 
 // implementation, close to no-op
 export function defineComponent(options: unknown) {
-  return isFunction(options)
-    ? { setup: options, name: options.name }
-    : options
+  return isFunction(options) ? { setup: options, name: options.name } : options
 }
index ccb26710e91cf5482807050b9aa34309e99e34d7..74a6ef770cdcf3e2833905bb498132366da351a0 100644 (file)
@@ -5,7 +5,7 @@ import {
   setCurrentInstance,
   isInSSRComponentSetup
 } from './component'
-import { ComponentPublicInstance } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstance'
 import { callWithAsyncErrorHandling, ErrorTypeStrings } from './errorHandling'
 import { warn } from './warning'
 import { capitalize } from '@vue/shared'
index cfc1a531b86c898b87808c3f0aa09f9653b52143..8f770f5a23b294213b06c1f049612430b34acc1a 100644 (file)
@@ -7,14 +7,14 @@ import {
   proxyRefs
 } from '@vue/reactivity'
 import {
-  CreateComponentPublicInstance,
   ComponentPublicInstance,
   PublicInstanceProxyHandlers,
   RuntimeCompiledPublicInstanceProxyHandlers,
   createRenderContext,
   exposePropsOnRenderContext,
-  exposeSetupStateOnRenderContext
-} from './componentProxy'
+  exposeSetupStateOnRenderContext,
+  ComponentPublicInstanceConstructor
+} from './componentPublicInstance'
 import {
   ComponentPropsOptions,
   NormalizedPropsOptions,
@@ -110,21 +110,19 @@ export interface ClassComponent {
   __vccOpts: ComponentOptions
 }
 
-export type Component = ComponentOptions | FunctionalComponent<any, any>
-
-// A type used in public APIs where a component type is expected.
-// The constructor type is an artificial type returned by defineComponent().
-export type PublicAPIComponent =
-  | Component
-  | {
-      new (...args: any[]): CreateComponentPublicInstance<
-        any,
-        any,
-        any,
-        any,
-        any
-      >
-    }
+/**
+ * Concrete component type matches its actual value: it's either an options
+ * object, or a function. Use this where the code expects to work with actual
+ * values, e.g. checking if its a function or not. This is mostly for internal
+ * implementation code.
+ */
+export type ConcreteComponent = ComponentOptions | FunctionalComponent<any, any>
+
+/**
+ * A type used in public APIs where a component type is expected.
+ * The constructor type is an artificial type returned by defineComponent().
+ */
+export type Component = ConcreteComponent | ComponentPublicInstanceConstructor
 
 export { ComponentOptions }
 
@@ -174,7 +172,7 @@ export type InternalRenderFunction = {
  */
 export interface ComponentInternalInstance {
   uid: number
-  type: Component
+  type: ConcreteComponent
   parent: ComponentInternalInstance | null
   root: ComponentInternalInstance
   appContext: AppContext
@@ -346,7 +344,7 @@ export function createComponentInstance(
   parent: ComponentInternalInstance | null,
   suspense: SuspenseBoundary | null
 ) {
-  const type = vnode.type as Component
+  const type = vnode.type as ConcreteComponent
   // inherit parent app context - or - if root, adopt from root vnode
   const appContext =
     (parent ? parent.appContext : vnode.appContext) || emptyAppContext
@@ -703,7 +701,7 @@ const classify = (str: string): string =>
 /* istanbul ignore next */
 export function formatComponentName(
   instance: ComponentInternalInstance | null,
-  Component: Component,
+  Component: ConcreteComponent,
   isRoot = false
 ): string {
   let name = isFunction(Component)
index 5c6a4959f9f67a049013bccb0883fd2cb49a8729..d75bc28ea12eecb4a8fe8e95e2cca76d648de025 100644 (file)
@@ -8,7 +8,7 @@ import {
   isFunction,
   extend
 } from '@vue/shared'
-import { ComponentInternalInstance, Component } from './component'
+import { ComponentInternalInstance, ConcreteComponent } from './component'
 import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
 import { warn } from './warning'
 import { normalizePropsOptions } from './componentProps'
@@ -94,7 +94,7 @@ export function emit(
 }
 
 function normalizeEmitsOptions(
-  comp: Component
+  comp: ConcreteComponent
 ): ObjectEmitsOptions | undefined {
   if (hasOwn(comp, '__emits')) {
     return comp.__emits
@@ -131,7 +131,7 @@ function normalizeEmitsOptions(
 // Check if an incoming prop key is a declared emit event listener.
 // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
 // both considered matched listeners.
-export function isEmitListener(comp: Component, key: string): boolean {
+export function isEmitListener(comp: ConcreteComponent, key: string): boolean {
   let emits: ObjectEmitsOptions | undefined
   if (!isOn(key) || !(emits = normalizeEmitsOptions(comp))) {
     return false
index 9c9e2c13a736d8a6b00e582e5a87c8e9a8378662..bb7a32ecef2c13dcfa831467f813dbdf85ba3f9a 100644 (file)
@@ -3,8 +3,8 @@ import {
   Data,
   SetupContext,
   ComponentInternalOptions,
-  PublicAPIComponent,
   Component,
+  ConcreteComponent,
   InternalRenderFunction
 } from './component'
 import {
@@ -52,7 +52,7 @@ import { Directive } from './directives'
 import {
   CreateComponentPublicInstance,
   ComponentPublicInstance
-} from './componentProxy'
+} from './componentPublicInstance'
 import { warn } from './warning'
 import { VNodeChild } from './vnode'
 
@@ -103,7 +103,7 @@ export interface ComponentOptionsBase<
   // Luckily `render()` doesn't need any arguments nor does it care about return
   // type.
   render?: Function
-  components?: Record<string, PublicAPIComponent>
+  components?: Record<string, Component>
   directives?: Record<string, Directive>
   inheritAttrs?: boolean
   emits?: (E | EE[]) & ThisType<void>
@@ -132,7 +132,7 @@ export interface ComponentOptionsBase<
    * marker for AsyncComponentWrapper
    * @internal
    */
-  __asyncLoader?: () => Promise<Component>
+  __asyncLoader?: () => Promise<ConcreteComponent>
   /**
    * cache for merged $options
    * @internal
index b07ca81d875026cd090582c4c170abea3bfe9f2f..48636f6553c7f62b7347611560c9791e25d40a70 100644 (file)
@@ -27,7 +27,7 @@ import {
   Data,
   ComponentInternalInstance,
   ComponentOptions,
-  Component
+  ConcreteComponent
 } from './component'
 import { isEmitListener } from './componentEmits'
 import { InternalObjectKey } from './vnode'
@@ -310,7 +310,7 @@ function resolvePropValue(
 }
 
 export function normalizePropsOptions(
-  comp: Component
+  comp: ConcreteComponent
 ): NormalizedPropsOptions | [] {
   if (comp.__props) {
     return comp.__props
@@ -411,7 +411,7 @@ function getTypeIndex(
 /**
  * dev only
  */
-function validateProps(props: Data, comp: Component) {
+function validateProps(props: Data, comp: ConcreteComponent) {
   const rawValues = toRaw(props)
   const options = normalizePropsOptions(comp)[0]
   for (const key in options) {
similarity index 99%
rename from packages/runtime-core/src/componentProxy.ts
rename to packages/runtime-core/src/componentPublicInstance.ts
index 9c31246539f6ae852fb58841a2cde395249c4c79..2205e1ae484bc5888c433f8b9880d7ef792f05bb 100644 (file)
@@ -101,6 +101,15 @@ type UnwrapMixinsType<
 
 type EnsureNonVoid<T> = T extends void ? {} : T
 
+export type ComponentPublicInstanceConstructor<
+  T extends ComponentPublicInstance = ComponentPublicInstance<any>
+> = {
+  __isFragment?: never
+  __isTeleport?: never
+  __isSuspense?: never
+  new (): T
+}
+
 export type CreateComponentPublicInstance<
   P = {},
   B = {},
@@ -162,12 +171,6 @@ export type ComponentPublicInstance<
   M &
   ComponentCustomProperties
 
-export type ComponentPublicInstanceConstructor<
-  T extends ComponentPublicInstance
-> = {
-  new (): T
-}
-
 type PublicPropertiesMap = Record<string, (i: ComponentInternalInstance) => any>
 
 const publicPropertiesMap: PublicPropertiesMap = extend(Object.create(null), {
index f7d42dab66133316352cc4ab4847e5e7f511d0bc..cc821650dab2a11ea82c2f193b6650f8a8bf8bd8 100644 (file)
@@ -1,5 +1,5 @@
 import {
-  Component,
+  ConcreteComponent,
   getCurrentInstance,
   FunctionalComponent,
   SetupContext,
@@ -33,7 +33,7 @@ import {
   invokeVNodeHook
 } from '../renderer'
 import { setTransitionHooks } from './BaseTransition'
-import { ComponentRenderContext } from '../componentProxy'
+import { ComponentRenderContext } from '../componentPublicInstance'
 
 type MatchPattern = string | RegExp | string[] | RegExp[]
 
@@ -43,7 +43,7 @@ export interface KeepAliveProps {
   max?: number | string
 }
 
-type CacheKey = string | number | Component
+type CacheKey = string | number | ConcreteComponent
 type Cache = Map<CacheKey, VNode>
 type Keys = Set<CacheKey>
 
@@ -151,7 +151,7 @@ const KeepAliveImpl = {
 
     function pruneCache(filter?: (name: string) => boolean) {
       cache.forEach((vnode, key) => {
-        const name = getName(vnode.type as Component)
+        const name = getName(vnode.type as ConcreteComponent)
         if (name && (!filter || !filter(name))) {
           pruneCacheEntry(key)
         }
@@ -228,7 +228,7 @@ const KeepAliveImpl = {
         return vnode
       }
 
-      const comp = vnode.type as Component
+      const comp = vnode.type as ConcreteComponent
       const name = getName(comp)
       const { include, exclude, max } = props
 
@@ -291,7 +291,7 @@ export const KeepAlive = (KeepAliveImpl as any) as {
   }
 }
 
-function getName(comp: Component): string | void {
+function getName(comp: ConcreteComponent): string | void {
   return (comp as FunctionalComponent).displayName || comp.name
 }
 
index 2799600951ac549b381517da2dec423160402197..b92e4b93ea575d09c671db06139e1eafc0eee9f6 100644 (file)
@@ -17,7 +17,7 @@ import { warn } from './warning'
 import { ComponentInternalInstance, Data } from './component'
 import { currentRenderingInstance } from './componentRenderUtils'
 import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
-import { ComponentPublicInstance } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstance'
 
 export interface DirectiveBinding<V = any> {
   instance: ComponentPublicInstance | null
index 42d9c9714384a6878816cd2577b48149687cea59..14ddece792c3530e025c0477ca12fb880ef1a4ce 100644 (file)
@@ -68,11 +68,6 @@ interface Constructor<P = any> {
   new (): { $props: P }
 }
 
-// Excludes Component type from returned `defineComponent`
-type NotDefinedComponent<T extends Component> = T extends Constructor
-  ? never
-  : T
-
 // The following is a series of overloads for providing props validation of
 // manually written render functions.
 
@@ -117,9 +112,9 @@ export function h<P, E extends EmitsOptions = {}>(
 // catch-all for generic component types
 export function h(type: Component, children?: RawChildren): VNode
 
-// exclude `defineComponent`
-export function h<Options extends ComponentOptions | FunctionalComponent<{}>>(
-  type: NotDefinedComponent<Options>,
+// exclude `defineComponent` constructors
+export function h<T extends ComponentOptions | FunctionalComponent<{}>>(
+  type: T,
   props?: RawProps | null,
   children?: RawChildren | RawSlots
 ): VNode
index 3272317dfb978975c8a447b3248c983f87f91828..4a20c747411dbe8c381801544b36ddec5a2ac141 100644 (file)
@@ -1,7 +1,7 @@
 import { currentRenderingInstance } from '../componentRenderUtils'
 import {
   currentInstance,
-  Component,
+  ConcreteComponent,
   FunctionalComponent,
   ComponentOptions
 } from '../component'
@@ -16,7 +16,9 @@ const DIRECTIVES = 'directives'
 /**
  * @private
  */
-export function resolveComponent(name: string): Component | string | undefined {
+export function resolveComponent(
+  name: string
+): ConcreteComponent | string | undefined {
   return resolveAsset(COMPONENTS, name) || name
 }
 
@@ -49,7 +51,7 @@ function resolveAsset(
   type: typeof COMPONENTS,
   name: string,
   warnMissing?: boolean
-): Component | undefined
+): ConcreteComponent | undefined
 // overload 2: directives
 function resolveAsset(
   type: typeof DIRECTIVES,
index a2f0022d8f74f6e140b6afa10631fa393b175b4d..b831498baa4dec0b3ba9859d0389f0c4c7de9541 100644 (file)
@@ -1,6 +1,6 @@
 /* eslint-disable no-restricted-globals */
 import {
-  Component,
+  ConcreteComponent,
   ComponentInternalInstance,
   ComponentOptions,
   InternalRenderFunction
@@ -10,7 +10,7 @@ import { extend } from '@vue/shared'
 
 export let isHmrUpdating = false
 
-export const hmrDirtyComponents = new Set<Component>()
+export const hmrDirtyComponents = new Set<ConcreteComponent>()
 
 export interface HMRRuntime {
   createRecord: typeof createRecord
index 14283b5d46bb991ce8410bd6ee41389ae3eb6434..e60c0a993977331cb60bcef97785d132afa81832 100644 (file)
@@ -159,6 +159,7 @@ export {
 } from './vnode'
 export {
   Component,
+  ConcreteComponent,
   FunctionalComponent,
   ComponentInternalInstance,
   SetupContext,
@@ -178,7 +179,7 @@ export {
 export {
   ComponentPublicInstance,
   ComponentCustomProperties
-} from './componentProxy'
+} from './componentPublicInstance'
 export {
   Renderer,
   RendererNode,
index 48336ebb905c77bb80efe62ca2f8fbe9ab89926a..97e4bf06c3a86353ccb0fdfb8467fc449b46954d 100644 (file)
@@ -66,7 +66,7 @@ import {
 import { createHydrationFunctions, RootHydrateFunction } from './hydration'
 import { invokeDirectiveHook } from './directives'
 import { startMeasure, endMeasure } from './profiling'
-import { ComponentPublicInstance } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstance'
 import { devtoolsComponentRemoved, devtoolsComponentUpdated } from './devtools'
 import { initFeatureFlags } from './featureFlags'
 
index e2bb819528ea8b80574b091502b6eae48bae06b0..2f5a6bfaca188afd0a8d7910015ad0d54097bdf6 100644 (file)
@@ -15,8 +15,9 @@ import {
 import {
   ComponentInternalInstance,
   Data,
-  Component,
-  ClassComponent
+  ConcreteComponent,
+  ClassComponent,
+  Component
 } from './component'
 import { RawSlots } from './componentSlots'
 import { isProxy, Ref, toRaw } from '@vue/reactivity'
@@ -244,7 +245,7 @@ export function isSameVNodeType(n1: VNode, n2: VNode): boolean {
   if (
     __DEV__ &&
     n2.shapeFlag & ShapeFlags.COMPONENT &&
-    hmrDirtyComponents.has(n2.type as Component)
+    hmrDirtyComponents.has(n2.type as ConcreteComponent)
   ) {
     // HMR only: if the component has been hot-updated, force a reload.
     return false
index f297d92607f41e4462d7caff8d32dd7072855c86..ad58778e91326cf6aaa46ae351eabfc4e5662bab 100644 (file)
@@ -2,7 +2,7 @@ import { VNode } from './vnode'
 import {
   Data,
   ComponentInternalInstance,
-  Component,
+  ConcreteComponent,
   formatComponentName
 } from './component'
 import { isString, isFunction } from '@vue/shared'
@@ -10,7 +10,7 @@ import { toRaw, isRef, pauseTracking, resetTracking } from '@vue/reactivity'
 import { callWithErrorHandling, ErrorCodes } from './errorHandling'
 
 type ComponentVNode = VNode & {
-  type: Component
+  type: ConcreteComponent
 }
 
 const stack: VNode[] = []
index 6918db61c8e695c946217ea9d90f1af424ef5f47..00dbe3c13aadad59fa29565de6dda6a793f2b95c 100644 (file)
@@ -1,5 +1,6 @@
 import {
   describe,
+  Component,
   defineComponent,
   PropType,
   ref,
@@ -179,6 +180,8 @@ describe('with object props', () => {
     }
   })
 
+  expectType<Component>(MyComponent)
+
   // Test TSX
   expectType<JSX.Element>(
     <MyComponent
@@ -205,6 +208,17 @@ describe('with object props', () => {
     />
   )
 
+  expectType<Component>(
+    <MyComponent
+      b="b"
+      dd={{ n: 1 }}
+      ddd={['ddd']}
+      eee={() => ({ a: 'eee' })}
+      fff={(a, b) => ({ a: a > +b })}
+      hhh={false}
+    />
+  )
+
   // @ts-expect-error missing required props
   expectError(<MyComponent />)
 
index b4dc19bb4d56d3295dadab71dc1c61ed9a194810..4376eaf979e201cd5d3668a31d814d15111cc414 100644 (file)
@@ -38,7 +38,7 @@ describe('h inference w/ Fragment', () => {
   // only accepts array children
   h(Fragment, ['hello'])
   h(Fragment, { key: 123 }, ['hello'])
-  //  @ts-expect-error
+  // @ts-expect-error
   expectError(h(Fragment, 'foo'))
   //  @ts-expect-error
   expectError(h(Fragment, { key: 123 }, 'bar'))
@@ -46,11 +46,11 @@ describe('h inference w/ Fragment', () => {
 
 describe('h inference w/ Teleport', () => {
   h(Teleport, { to: '#foo' }, 'hello')
-  //  @ts-expect-error
+  // @ts-expect-error
   expectError(h(Teleport))
-  //  @ts-expect-error
+  // @ts-expect-error
   expectError(h(Teleport, {}))
-  //  @ts-expect-error
+  // @ts-expect-error
   expectError(h(Teleport, { to: '#foo' }))
 })
 
@@ -148,6 +148,7 @@ describe('h support for generic component type', () => {
   function foo(bar: Component) {
     h(bar)
     h(bar, 'hello')
+    // @ts-expect-error
     h(bar, { id: 'ok' }, 'hello')
   }
   foo({})