watch,
watchEffect,
onUnmounted,
- onErrorCaptured,
- Component
+ onErrorCaptured
} from '@vue/runtime-test'
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
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>
export interface AsyncComponentOptions<T = any> {
loader: AsyncComponentLoader<T>
- loadingComponent?: PublicAPIComponent
- errorComponent?: PublicAPIComponent
+ loadingComponent?: Component
+ errorComponent?: Component
delay?: number
timeout?: number
suspensible?: boolean
}
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 }
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 = () => {
return load()
}
- const load = (): Promise<Component> => {
- let thisRequest: Promise<Component>
+ const load = (): Promise<ConcreteComponent> => {
+ let thisRequest: Promise<ConcreteComponent>
return (
pendingRequest ||
(thisRequest = pendingRequest = loader()
onError(err)
return () =>
errorComponent
- ? createVNode(errorComponent as Component, { error: err })
+ ? createVNode(errorComponent as ConcreteComponent, {
+ error: err
+ })
: null
})
}
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)
}
}
}
}
function createInnerComp(
- comp: Component,
+ comp: ConcreteComponent,
{ vnode: { props, children } }: ComponentInternalInstance
) {
return createVNode(comp, props, children)
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'
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(
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
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
}
export type CreateAppFunction<HostElement> = (
- rootComponent: PublicAPIComponent,
+ rootComponent: Component,
rootProps?: Data | null
) => App<HostElement>
let isMounted = false
const app: App = (context.app = {
- _component: rootComponent as Component,
+ _component: rootComponent as ConcreteComponent,
_props: rootProps,
_container: null,
_context: context,
return app
},
- component(name: string, component?: PublicAPIComponent): any {
+ component(name: string, component?: Component): any {
if (__DEV__) {
validateComponentName(name, context.config)
}
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
import {
CreateComponentPublicInstance,
ComponentPublicInstanceConstructor
-} from './componentProxy'
+} from './componentPublicInstance'
import { ExtractPropTypes, ComponentPropsOptions } from './componentProps'
import { EmitsOptions } from './componentEmits'
import { isFunction } from '@vue/shared'
// 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
}
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'
proxyRefs
} from '@vue/reactivity'
import {
- CreateComponentPublicInstance,
ComponentPublicInstance,
PublicInstanceProxyHandlers,
RuntimeCompiledPublicInstanceProxyHandlers,
createRenderContext,
exposePropsOnRenderContext,
- exposeSetupStateOnRenderContext
-} from './componentProxy'
+ exposeSetupStateOnRenderContext,
+ ComponentPublicInstanceConstructor
+} from './componentPublicInstance'
import {
ComponentPropsOptions,
NormalizedPropsOptions,
__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 }
*/
export interface ComponentInternalInstance {
uid: number
- type: Component
+ type: ConcreteComponent
parent: ComponentInternalInstance | null
root: ComponentInternalInstance
appContext: AppContext
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
/* istanbul ignore next */
export function formatComponentName(
instance: ComponentInternalInstance | null,
- Component: Component,
+ Component: ConcreteComponent,
isRoot = false
): string {
let name = isFunction(Component)
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'
}
function normalizeEmitsOptions(
- comp: Component
+ comp: ConcreteComponent
): ObjectEmitsOptions | undefined {
if (hasOwn(comp, '__emits')) {
return comp.__emits
// 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
Data,
SetupContext,
ComponentInternalOptions,
- PublicAPIComponent,
Component,
+ ConcreteComponent,
InternalRenderFunction
} from './component'
import {
import {
CreateComponentPublicInstance,
ComponentPublicInstance
-} from './componentProxy'
+} from './componentPublicInstance'
import { warn } from './warning'
import { VNodeChild } from './vnode'
// 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>
* marker for AsyncComponentWrapper
* @internal
*/
- __asyncLoader?: () => Promise<Component>
+ __asyncLoader?: () => Promise<ConcreteComponent>
/**
* cache for merged $options
* @internal
Data,
ComponentInternalInstance,
ComponentOptions,
- Component
+ ConcreteComponent
} from './component'
import { isEmitListener } from './componentEmits'
import { InternalObjectKey } from './vnode'
}
export function normalizePropsOptions(
- comp: Component
+ comp: ConcreteComponent
): NormalizedPropsOptions | [] {
if (comp.__props) {
return comp.__props
/**
* 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) {
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 = {},
M &
ComponentCustomProperties
-export type ComponentPublicInstanceConstructor<
- T extends ComponentPublicInstance
-> = {
- new (): T
-}
-
type PublicPropertiesMap = Record<string, (i: ComponentInternalInstance) => any>
const publicPropertiesMap: PublicPropertiesMap = extend(Object.create(null), {
import {
- Component,
+ ConcreteComponent,
getCurrentInstance,
FunctionalComponent,
SetupContext,
invokeVNodeHook
} from '../renderer'
import { setTransitionHooks } from './BaseTransition'
-import { ComponentRenderContext } from '../componentProxy'
+import { ComponentRenderContext } from '../componentPublicInstance'
type MatchPattern = string | RegExp | string[] | RegExp[]
max?: number | string
}
-type CacheKey = string | number | Component
+type CacheKey = string | number | ConcreteComponent
type Cache = Map<CacheKey, VNode>
type Keys = Set<CacheKey>
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)
}
return vnode
}
- const comp = vnode.type as Component
+ const comp = vnode.type as ConcreteComponent
const name = getName(comp)
const { include, exclude, max } = props
}
}
-function getName(comp: Component): string | void {
+function getName(comp: ConcreteComponent): string | void {
return (comp as FunctionalComponent).displayName || comp.name
}
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
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.
// 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
import { currentRenderingInstance } from '../componentRenderUtils'
import {
currentInstance,
- Component,
+ ConcreteComponent,
FunctionalComponent,
ComponentOptions
} from '../component'
/**
* @private
*/
-export function resolveComponent(name: string): Component | string | undefined {
+export function resolveComponent(
+ name: string
+): ConcreteComponent | string | undefined {
return resolveAsset(COMPONENTS, name) || name
}
type: typeof COMPONENTS,
name: string,
warnMissing?: boolean
-): Component | undefined
+): ConcreteComponent | undefined
// overload 2: directives
function resolveAsset(
type: typeof DIRECTIVES,
/* eslint-disable no-restricted-globals */
import {
- Component,
+ ConcreteComponent,
ComponentInternalInstance,
ComponentOptions,
InternalRenderFunction
export let isHmrUpdating = false
-export const hmrDirtyComponents = new Set<Component>()
+export const hmrDirtyComponents = new Set<ConcreteComponent>()
export interface HMRRuntime {
createRecord: typeof createRecord
} from './vnode'
export {
Component,
+ ConcreteComponent,
FunctionalComponent,
ComponentInternalInstance,
SetupContext,
export {
ComponentPublicInstance,
ComponentCustomProperties
-} from './componentProxy'
+} from './componentPublicInstance'
export {
Renderer,
RendererNode,
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'
import {
ComponentInternalInstance,
Data,
- Component,
- ClassComponent
+ ConcreteComponent,
+ ClassComponent,
+ Component
} from './component'
import { RawSlots } from './componentSlots'
import { isProxy, Ref, toRaw } from '@vue/reactivity'
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
import {
Data,
ComponentInternalInstance,
- Component,
+ ConcreteComponent,
formatComponentName
} from './component'
import { isString, isFunction } from '@vue/shared'
import { callWithErrorHandling, ErrorCodes } from './errorHandling'
type ComponentVNode = VNode & {
- type: Component
+ type: ConcreteComponent
}
const stack: VNode[] = []
import {
describe,
+ Component,
defineComponent,
PropType,
ref,
}
})
+ expectType<Component>(MyComponent)
+
// Test TSX
expectType<JSX.Element>(
<MyComponent
/>
)
+ 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 />)
// 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'))
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' }))
})
function foo(bar: Component) {
h(bar)
h(bar, 'hello')
+ // @ts-expect-error
h(bar, { id: 'ok' }, 'hello')
}
foo({})