types(runtime-core): refactor defineComponent (#1883)

This commit is contained in:
Carlos Rodrigues
2020-09-15 16:46:11 +01:00
committed by GitHub
parent 848ccf56fb
commit 4fd468aced
8 changed files with 583 additions and 132 deletions

View File

@@ -6,22 +6,65 @@ import {
ComponentOptionsWithObjectProps,
ComponentOptionsMixin,
RenderFunction,
UnwrapAsyncBindings
ComponentOptionsBase
} from './componentOptions'
import {
SetupContext,
FunctionalComponent,
AllowedComponentProps,
ComponentCustomProps
} from './component'
import {
CreateComponentPublicInstance,
ComponentPublicInstanceConstructor
} from './componentPublicInstance'
import { ExtractPropTypes, ComponentPropsOptions } from './componentProps'
import { EmitsOptions } from './componentEmits'
import { isFunction } from '@vue/shared'
import { VNodeProps } from './vnode'
import {
CreateComponentPublicInstance,
ComponentPublicInstanceConstructor
} from './componentPublicInstance'
export type PublicProps = VNodeProps &
AllowedComponentProps &
ComponentCustomProps
export type DefineComponent<
PropsOrPropOptions = any,
RawBindings = any,
D = any,
C extends ComputedOptions = ComputedOptions,
M extends MethodOptions = MethodOptions,
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>,
EE extends string = string,
PP = PublicProps,
RequiredProps = Readonly<ExtractPropTypes<PropsOrPropOptions>>,
OptionalProps = Readonly<ExtractPropTypes<PropsOrPropOptions, false>>
> = ComponentPublicInstanceConstructor<
CreateComponentPublicInstance<
OptionalProps,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
PP & OptionalProps
> &
RequiredProps
> &
ComponentOptionsBase<
RequiredProps,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE
> &
PP
// defineComponent is a utility that is primarily used for type inference
// when declaring components. Type inference is provided in the component
@@ -35,21 +78,7 @@ export function defineComponent<Props, RawBindings = object>(
props: Readonly<Props>,
ctx: SetupContext
) => RawBindings | RenderFunction
): ComponentPublicInstanceConstructor<
CreateComponentPublicInstance<
Props,
UnwrapAsyncBindings<RawBindings>,
{},
{},
{},
{},
{},
{},
// public props
VNodeProps & Props & AllowedComponentProps & ComponentCustomProps
>
> &
FunctionalComponent<Props>
): DefineComponent<Props, RawBindings>
// overload 2: object format with no props
// (uses user defined props interface)
@@ -58,11 +87,11 @@ export function defineComponent<
Props = {},
RawBindings = {},
D = {},
C extends ComputedOptions = {},
M extends MethodOptions = {},
C extends ComputedOptions = ComputedOptions,
M extends MethodOptions = MethodOptions,
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>,
E extends EmitsOptions = EmitsOptions,
EE extends string = string
>(
options: ComponentOptionsWithoutProps<
@@ -76,30 +105,7 @@ export function defineComponent<
E,
EE
>
): ComponentPublicInstanceConstructor<
CreateComponentPublicInstance<
Props,
UnwrapAsyncBindings<RawBindings>,
D,
C,
M,
Mixin,
Extends,
E,
VNodeProps & Props & AllowedComponentProps & ComponentCustomProps
>
> &
ComponentOptionsWithoutProps<
Props,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE
>
): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>
// overload 3: object format with array props declaration
// props inferred as { [key in PropNames]?: any }
@@ -126,32 +132,17 @@ export function defineComponent<
E,
EE
>
): ComponentPublicInstanceConstructor<
// array props technically doesn't place any constraints on props in TSX before,
// but now we can export array props in TSX
CreateComponentPublicInstance<
Readonly<{ [key in PropNames]?: any }>,
UnwrapAsyncBindings<RawBindings>,
D,
C,
M,
Mixin,
Extends,
E,
AllowedComponentProps & ComponentCustomProps
>
> &
ComponentOptionsWithArrayProps<
PropNames,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE
>
): DefineComponent<
Readonly<{ [key in PropNames]?: any }>,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE
>
// overload 4: object format with object props declaration
// see `ExtractPropTypes` in ./componentProps.ts
@@ -179,33 +170,20 @@ export function defineComponent<
E,
EE
>
): ComponentPublicInstanceConstructor<
CreateComponentPublicInstance<
ExtractPropTypes<PropsOptions, false>,
UnwrapAsyncBindings<RawBindings>,
D,
C,
M,
Mixin,
Extends,
E,
VNodeProps & AllowedComponentProps & ComponentCustomProps
> &
Readonly<ExtractPropTypes<PropsOptions>>
> &
ComponentOptionsWithObjectProps<
PropsOptions,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE
>
): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>
// implementation, close to no-op
export function defineComponent(options: unknown) {
return isFunction(options) ? { setup: options, name: options.name } : options
}
defineComponent({
async setup() {
return {
a: 123
}
},
render() {
this.a
}
})

View File

@@ -26,7 +26,12 @@ import { warn } from './warning'
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
import { Directive, validateDirectiveName } from './directives'
import { applyOptions, ComponentOptions } from './componentOptions'
import {
applyOptions,
ComponentOptions,
ComputedOptions,
MethodOptions
} from './componentOptions'
import {
EmitsOptions,
ObjectEmitsOptions,
@@ -118,13 +123,29 @@ export interface ClassComponent {
* values, e.g. checking if its a function or not. This is mostly for internal
* implementation code.
*/
export type ConcreteComponent = ComponentOptions | FunctionalComponent<any, any>
export type ConcreteComponent<
Props = {},
RawBindings = any,
D = any,
C extends ComputedOptions = ComputedOptions,
M extends MethodOptions = MethodOptions
> =
| ComponentOptions<Props, RawBindings, D, C, M>
| FunctionalComponent<Props, 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 type Component<
Props = any,
RawBindings = any,
D = any,
C extends ComputedOptions = ComputedOptions,
M extends MethodOptions = MethodOptions
> =
| ConcreteComponent<Props, RawBindings, D, C, M>
| ComponentPublicInstanceConstructor<Props>
export { ComponentOptions }

View File

@@ -72,8 +72,6 @@ export interface ComponentCustomOptions {}
export type RenderFunction = () => VNodeChild
export type UnwrapAsyncBindings<T> = T extends Promise<infer S> ? S : T
export interface ComponentOptionsBase<
Props,
RawBindings,
@@ -92,7 +90,7 @@ export interface ComponentOptionsBase<
this: void,
props: Props,
ctx: SetupContext<E>
) => RawBindings | RenderFunction | void
) => Promise<RawBindings> | RawBindings | RenderFunction | void
name?: string
template?: string | object // can be a direct DOM node
// Note: we are intentionally using the signature-less `Function` type here
@@ -230,10 +228,29 @@ export type ComponentOptionsWithObjectProps<
>
>
export type ComponentOptions =
| ComponentOptionsWithoutProps<any, any, any, any, any>
| ComponentOptionsWithObjectProps<any, any, any, any, any>
| ComponentOptionsWithArrayProps<any, any, any, any, any>
export type ComponentOptions<
Props = {},
RawBindings = any,
D = any,
C extends ComputedOptions = any,
M extends MethodOptions = any,
Mixin extends ComponentOptionsMixin = any,
Extends extends ComponentOptionsMixin = any,
E extends EmitsOptions = any
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E> &
ThisType<
CreateComponentPublicInstance<
{},
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
Readonly<Props>
>
>
export type ComponentOptionsMixin = ComponentOptionsBase<
any,
@@ -638,17 +655,13 @@ export function applyOptions(
onRenderTriggered(renderTriggered.bind(publicThis))
}
if (__DEV__ && beforeDestroy) {
warn(
`\`beforeDestroy\` has been renamed to \`beforeUnmount\`.`
)
warn(`\`beforeDestroy\` has been renamed to \`beforeUnmount\`.`)
}
if (beforeUnmount) {
onBeforeUnmount(beforeUnmount.bind(publicThis))
}
if (__DEV__ && destroyed) {
warn(
`\`destroyed\` has been renamed to \`unmounted\`.`
)
warn(`\`destroyed\` has been renamed to \`unmounted\`.`)
}
if (unmounted) {
onUnmounted(unmounted.bind(publicThis))

View File

@@ -27,8 +27,7 @@ import {
OptionTypesType,
OptionTypesKeys,
resolveMergedOptions,
isInBeforeCreate,
UnwrapAsyncBindings
isInBeforeCreate
} from './componentOptions'
import { EmitsOptions, EmitFn } from './componentEmits'
import { Slots } from './componentSlots'
@@ -102,7 +101,18 @@ type UnwrapMixinsType<
type EnsureNonVoid<T> = T extends void ? {} : T
export type ComponentPublicInstanceConstructor<
T extends ComponentPublicInstance = ComponentPublicInstance<any>
T extends ComponentPublicInstance<
Props,
RawBindings,
D,
C,
M
> = ComponentPublicInstance<any>,
Props = any,
RawBindings = any,
D = any,
C extends ComputedOptions = ComputedOptions,
M extends MethodOptions = MethodOptions
> = {
__isFragment?: never
__isTeleport?: never
@@ -138,6 +148,7 @@ export type CreateComponentPublicInstance<
PublicProps,
ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E>
>
// public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option)
export type ComponentPublicInstance<
@@ -169,7 +180,7 @@ export type ComponentPublicInstance<
options?: WatchOptions
): WatchStopHandle
} & P &
ShallowUnwrapRef<UnwrapAsyncBindings<B>> &
ShallowUnwrapRef<B> &
D &
ExtractComputedReturns<C> &
M &

View File

@@ -10,9 +10,9 @@ import { Teleport, TeleportProps } from './components/Teleport'
import { Suspense, SuspenseProps } from './components/Suspense'
import { isObject, isArray } from '@vue/shared'
import { RawSlots } from './componentSlots'
import { FunctionalComponent, Component } from './component'
import { ComponentOptions } from './componentOptions'
import { FunctionalComponent, Component, ComponentOptions } from './component'
import { EmitsOptions } from './componentEmits'
import { DefineComponent } from './apiDefineComponent'
// `h` is a more user-friendly version of `createVNode` that allows omitting the
// props when possible. It is intended for manually written render functions.
@@ -50,7 +50,7 @@ type RawProps = VNodeProps & {
__v_isVNode?: never
// used to differ from Array children
[Symbol.iterator]?: never
} & { [key: string]: any }
} & Record<string, any>
type RawChildren =
| string
@@ -112,10 +112,17 @@ export function h<P, E extends EmitsOptions = {}>(
// catch-all for generic component types
export function h(type: Component, children?: RawChildren): VNode
// component without props
export function h(
type: Component,
props: null,
children?: RawChildren | RawSlots
): VNode
// exclude `defineComponent` constructors
export function h<T extends ComponentOptions | FunctionalComponent<{}>>(
type: T,
props?: RawProps | null,
export function h<P>(
type: ComponentOptions<P>,
props?: (RawProps & P) | ({} extends P ? null : never),
children?: RawChildren | RawSlots
): VNode
@@ -127,6 +134,14 @@ export function h<P>(
children?: RawChildren | RawSlots
): VNode
// fake constructor type returned by `defineComponent`
export function h(type: DefineComponent, children?: RawChildren): VNode
export function h<P>(
type: DefineComponent<P>,
props?: (RawProps & P) | ({} extends P ? null : never),
children?: RawChildren | RawSlots
): VNode
// Actual implementation
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
const l = arguments.length

View File

@@ -41,7 +41,7 @@ export {
} from './apiLifecycle'
export { provide, inject } from './apiInject'
export { nextTick } from './scheduler'
export { defineComponent } from './apiDefineComponent'
export { defineComponent, DefineComponent } from './apiDefineComponent'
export { defineAsyncComponent } from './apiAsyncComponent'
// Advanced API ----------------------------------------------------------------