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