Data,
ComponentOptions,
currentRenderingInstance,
- currentInstance
+ currentInstance,
+ ComponentRenderProxy
} from './component'
import {
isFunction,
capitalize,
camelize
} from '@vue/shared'
-import { computed, ComputedOptions } from './apiReactivity'
-import { watch, WatchOptions } from './apiWatch'
+import { computed } from './apiReactivity'
+import { watch, WatchOptions, CleanupRegistrator } from './apiWatch'
import { provide, inject } from './apiInject'
import {
onBeforeMount,
// TODO legacy component definition also supports constructors with .options
type LegacyComponent = ComponentOptions
+export interface ComputedOptions {
+ [key: string]:
+ | Function
+ | {
+ get: Function
+ set: Function
+ }
+}
+
+export interface MethodOptions {
+ [key: string]: Function
+}
+
+export type ExtracComputedReturns<T extends any> = {
+ [key in keyof T]: T[key] extends { get: Function }
+ ? ReturnType<T[key]['get']>
+ : ReturnType<T[key]>
+}
+
+type WatchHandler = (
+ val: any,
+ oldVal: any,
+ onCleanup: CleanupRegistrator
+) => void
+
// TODO type inference for these options
-export interface LegacyOptions {
+export interface LegacyOptions<
+ Props,
+ RawBindings,
+ D,
+ C extends ComputedOptions,
+ M extends MethodOptions,
+ ThisContext = ThisType<ComponentRenderProxy<Props, D, RawBindings, C, M>>
+> {
el?: any
// state
- data?: Data | (() => Data)
- computed?: Record<string, (() => any) | ComputedOptions>
- methods?: Record<string, Function>
+ data?:
+ | D
+ | (<This extends ComponentRenderProxy<Props, {}, RawBindings>>(
+ this: This
+ ) => D)
+ computed?: C & ThisContext
+ methods?: M & ThisContext
// TODO watch array
watch?: Record<
string,
- string | Function | { handler: Function } & WatchOptions
- >
- provide?: Data | (() => Data)
+ string | WatchHandler | { handler: WatchHandler } & WatchOptions
+ > &
+ ThisContext
+ provide?:
+ | Data
+ | (<This extends ComponentRenderProxy<Props, D, RawBindings, C, M>>(
+ this: This
+ ) => any)
inject?:
| string[]
| Record<
extends?: LegacyComponent
// lifecycle
- beforeCreate?(): void
- created?(): void
+ beforeCreate?(this: ComponentRenderProxy): void
+ created?<This extends ComponentRenderProxy<Props, D, RawBindings, C, M>>(
+ this: This
+ ): void
beforeMount?(): void
mounted?(): void
beforeUpdate?(): void
}
if (computedOptions) {
for (const key in computedOptions) {
- const opt = computedOptions[key]
+ const opt = (computedOptions as ComputedOptions)[key]
data[key] = isFunction(opt)
? computed(opt.bind(ctx))
: computed({
}
if (methods) {
for (const key in methods) {
- data[key] = methods[key].bind(ctx)
+ data[key] = (methods as MethodOptions)[key].bind(ctx)
}
}
if (watchOptions) {
} from './errorHandling'
import { AppContext, createAppContext } from './apiApp'
import { Directive } from './directives'
-import { applyOptions, LegacyOptions, resolveAsset } from './apiOptions'
+import {
+ applyOptions,
+ LegacyOptions,
+ resolveAsset,
+ ComputedOptions,
+ MethodOptions,
+ ExtracComputedReturns
+} from './apiOptions'
export type Data = { [key: string]: unknown }
// public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option)
-export type ComponentRenderProxy<P = {}, S = {}, PublicProps = P> = {
- $data: S
+export type ComponentRenderProxy<
+ P = {},
+ D = {},
+ B = {},
+ C = {},
+ M = {},
+ PublicProps = P
+> = {
+ $data: D
$props: PublicProps
$attrs: Data
$refs: Data
$parent: ComponentInstance | null
$emit: (event: string, ...args: unknown[]) => void
} & P &
- S
+ D &
+ UnwrapRef<B> &
+ ExtracComputedReturns<C> &
+ M
-type RenderFunction<Props = {}, RawBindings = {}> = <
- Bindings extends UnwrapRef<RawBindings>
+type RenderFunction<P = {}, D = {}, B = {}, C = {}, M = {}> = <
+ This extends ComponentRenderProxy<P, D, B, C, M>
>(
- this: ComponentRenderProxy<Props, Bindings>
+ this: This
) => VNodeChild
-interface ComponentOptionsBase<Props, RawBindings> extends LegacyOptions {
+interface ComponentOptionsBase<
+ Props,
+ RawBindings,
+ D,
+ C extends ComputedOptions,
+ M extends MethodOptions
+> extends LegacyOptions<Props, RawBindings, D, C, M> {
setup?: (
props: Props,
ctx: SetupContext
) => RawBindings | (() => VNodeChild) | void
name?: string
template?: string
- render?: RenderFunction<Props, RawBindings>
+ render?: RenderFunction<Props, D, RawBindings, C, M>
components?: Record<string, Component>
directives?: Record<string, Directive>
}
-export interface ComponentOptionsWithoutProps<Props = {}, RawBindings = {}>
- extends ComponentOptionsBase<Props, RawBindings> {
+export interface ComponentOptionsWithoutProps<
+ Props = {},
+ RawBindings = {},
+ D = {},
+ C extends ComputedOptions = {},
+ M extends MethodOptions = {}
+> extends ComponentOptionsBase<Props, RawBindings, D, C, M> {
props?: undefined
}
export interface ComponentOptionsWithArrayProps<
PropNames extends string = string,
RawBindings = {},
+ D = {},
+ C extends ComputedOptions = {},
+ M extends MethodOptions = {},
Props = { [key in PropNames]?: unknown }
-> extends ComponentOptionsBase<Props, RawBindings> {
+> extends ComponentOptionsBase<Props, RawBindings, D, C, M> {
props: PropNames[]
}
export interface ComponentOptionsWithProps<
PropsOptions = ComponentPropsOptions,
RawBindings = {},
+ D = {},
+ C extends ComputedOptions = {},
+ M extends MethodOptions = {},
Props = ExtractPropTypes<PropsOptions>
-> extends ComponentOptionsBase<Props, RawBindings> {
+> extends ComponentOptionsBase<Props, RawBindings, D, C, M> {
props: PropsOptions
}
export type ComponentOptions =
- | ComponentOptionsWithProps
| ComponentOptionsWithoutProps
+ | ComponentOptionsWithProps
| ComponentOptionsWithArrayProps
export interface FunctionalComponent<P = {}> {
emit: ((event: string, ...args: unknown[]) => void)
}
-export type ComponentInstance<P = Data, S = Data> = {
+export type ComponentInstance<P = Data, D = Data> = {
type: FunctionalComponent | ComponentOptions
parent: ComponentInstance | null
appContext: AppContext
next: VNode | null
subTree: VNode
update: ReactiveEffect
- render: RenderFunction<P, S> | null
+ render: RenderFunction<P, D> | null
effects: ReactiveEffect[] | null
provides: Data
directives: Record<string, Directive>
// the rest are only for stateful components
- data: S
+ data: D
props: P
renderProxy: ComponentRenderProxy | null
propsProxy: P | null
// overload 2: object format with no props
// (uses user defined props interface)
// return type is for Vetur and TSX support
-export function createComponent<Props, RawBindings>(
- options: ComponentOptionsWithoutProps<Props, RawBindings>
+export function createComponent<
+ Props,
+ RawBindings,
+ D,
+ C extends ComputedOptions = {},
+ M extends MethodOptions = {}
+>(
+ options: ComponentOptionsWithoutProps<Props, RawBindings, D, C, M>
): {
- new (): ComponentRenderProxy<Props, UnwrapRef<RawBindings>>
+ new (): ComponentRenderProxy<Props, D, RawBindings, C, M>
}
// overload 3: object format with array props declaration
// props inferred as { [key in PropNames]?: unknown }
// return type is for Vetur and TSX support
-export function createComponent<PropNames extends string, RawBindings>(
- options: ComponentOptionsWithArrayProps<PropNames, RawBindings>
+export function createComponent<
+ PropNames extends string,
+ RawBindings,
+ D,
+ C extends ComputedOptions = {},
+ M extends MethodOptions = {}
+>(
+ options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
): {
new (): ComponentRenderProxy<
{ [key in PropNames]?: unknown },
- UnwrapRef<RawBindings>
+ D,
+ RawBindings,
+ C,
+ M
>
}
// overload 4: object format with object props declaration
// see `ExtractPropTypes` in ./componentProps.ts
-export function createComponent<PropsOptions, RawBindings>(
- options: ComponentOptionsWithProps<PropsOptions, RawBindings>
+export function createComponent<
+ PropsOptions,
+ RawBindings,
+ D,
+ C extends ComputedOptions = {},
+ M extends MethodOptions = {}
+>(
+ options: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
): {
// for Vetur and TSX support
new (): ComponentRenderProxy<
ExtractPropTypes<PropsOptions>,
- UnwrapRef<RawBindings>,
+ D,
+ RawBindings,
+ C,
+ M,
ExtractPropTypes<PropsOptions, false>
>
}