From a9b608266eff1150105f249ff88ce77712f2f4aa Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 13 Oct 2018 21:13:56 -0400 Subject: [PATCH] types: improve public component type --- packages/core/src/component.ts | 149 ++++++++++++++++---------- packages/core/src/componentOptions.ts | 4 +- packages/core/src/componentUtils.ts | 2 +- packages/core/src/h.ts | 10 +- packages/core/src/index.ts | 7 +- packages/core/src/vdom.ts | 1 + 6 files changed, 102 insertions(+), 71 deletions(-) diff --git a/packages/core/src/component.ts b/packages/core/src/component.ts index 984693d1..d08ce976 100644 --- a/packages/core/src/component.ts +++ b/packages/core/src/component.ts @@ -1,4 +1,4 @@ -import { EMPTY_OBJ } from './utils' +import { EMPTY_OBJ, NOOP } from './utils' import { VNode, Slots, RenderNode, MountedVNode } from './vdom' import { Data, @@ -13,37 +13,43 @@ import { nextTick } from '@vue/scheduler' import { ErrorTypes } from './errorHandling' import { initializeComponentInstance } from './componentUtils' -export interface ComponentClass extends ComponentClassOptions { - options?: ComponentOptions - new

(): MergedComponent +// public component instance type +export interface Component

extends PublicInstanceMethods { + readonly $el: any + readonly $vnode: MountedVNode + readonly $parentVNode: MountedVNode + readonly $data: D + readonly $props: Readonly

+ readonly $attrs: Readonly + readonly $slots: Slots + readonly $root: Component + readonly $parent: Component + readonly $children: Component[] + readonly $options: ComponentOptions + readonly $refs: Record + readonly $proxy: this } -export type MergedComponent = D & P & ComponentInstance - -export interface FunctionalComponent

{ - (props: P, slots: Slots, attrs: Data): any - pure?: boolean - props?: ComponentPropsOptions

- displayName?: string +interface PublicInstanceMethods { + $forceUpdate(): void + $nextTick(fn: () => any): Promise + $watch( + keyOrFn: string | ((this: this) => any), + cb: (this: this, newValue: any, oldValue: any) => void, + options?: WatchOptions + ): () => void + $on(event: string, fn: Function): this + $once(event: string, fn: Function): this + $off(event?: string, fn?: Function): this + $emit(name: string, ...payload: any[]): this } -export type ComponentType = ComponentClass | FunctionalComponent - -export interface ComponentInstance

extends InternalComponent { - constructor: ComponentClass - - $vnode: MountedVNode - $data: D - $props: Readonly

- $attrs: Data - $slots: Slots - $root: ComponentInstance - $children: ComponentInstance[] - +interface APIMethods { data?(): Partial render(props: Readonly

, slots: Slots, attrs: Data): any - renderTracked?(e: DebuggerEvent): void - renderTriggered?(e: DebuggerEvent): void +} + +interface LifecycleMethods { beforeCreate?(): void created?(): void beforeMount?(): void @@ -60,50 +66,83 @@ export interface ComponentInstance

extends InternalComponent { ) => boolean | void activated?(): void deactivated?(): void + renderTracked?(e: DebuggerEvent): void + renderTriggered?(e: DebuggerEvent): void +} + +export interface ComponentClass extends ComponentClassOptions { + options?: ComponentOptions + new

(): Component & D & P +} + +export interface FunctionalComponent

{ + (props: P, slots: Slots, attrs: Data): any + pure?: boolean + props?: ComponentPropsOptions

+ displayName?: string +} + +export type ComponentType = ComponentClass | FunctionalComponent + +// Internal type that represents a mounted instance. +// It extends InternalComponent with mounted instance properties. +export interface ComponentInstance

+ extends InternalComponent, + APIMethods, + LifecycleMethods { + constructor: ComponentClass + + $vnode: MountedVNode + $data: D + $props: P + $attrs: Data + $slots: Slots + $root: ComponentInstance + $children: ComponentInstance[] _updateHandle: Autorun _queueJob: ((fn: () => void) => void) - $forceUpdate: () => void - $nextTick: (fn: () => void) => Promise - _self: ComponentInstance // on proxies only } -class InternalComponent { - public get $el(): RenderNode | null { +// actual implementation of the component +class InternalComponent implements PublicInstanceMethods { + get $el(): any { return this.$vnode && this.$vnode.el } - public $vnode: VNode | null = null - public $parentVNode: VNode | null = null - public $data: Data | null = null - public $props: Data | null = null - public $attrs: Data | null = null - public $slots: Slots | null = null - public $root: ComponentInstance | null = null - public $parent: ComponentInstance | null = null - public $children: ComponentInstance[] = [] - public $options: ComponentOptions - public $refs: Record = {} - public $proxy: any = null - public $forceUpdate: (() => void) | null = null + $vnode: VNode | null = null + $parentVNode: VNode | null = null + $data: Data | null = null + $props: Data | null = null + $attrs: Data | null = null + $slots: Slots | null = null + $root: ComponentInstance | null = null + $parent: ComponentInstance | null = null + $children: ComponentInstance[] = [] + $options: ComponentOptions + $refs: Record = {} + $proxy: any = null - public _rawData: Data | null = null - public _computedGetters: Record | null = null - public _watchHandles: Set | null = null - public _mounted: boolean = false - public _unmounted: boolean = false - public _events: { [event: string]: Function[] | null } | null = null - public _updateHandle: Autorun | null = null - public _queueJob: ((fn: () => void) => void) | null = null - public _isVue: boolean = true - public _inactiveRoot: boolean = false + _rawData: Data | null = null + _computedGetters: Record | null = null + _watchHandles: Set | null = null + _mounted: boolean = false + _unmounted: boolean = false + _events: { [event: string]: Function[] | null } | null = null + _updateHandle: Autorun | null = null + _queueJob: ((fn: () => void) => void) | null = null + _isVue: boolean = true + _inactiveRoot: boolean = false constructor() { initializeComponentInstance(this as any) } - $nextTick(fn: () => any): Promise { + // to be set by renderer during mount + $forceUpdate: () => void = NOOP + + $nextTick(fn: () => any): Promise { return nextTick(fn) } diff --git a/packages/core/src/componentOptions.ts b/packages/core/src/componentOptions.ts index 08cf83c8..bd436fb9 100644 --- a/packages/core/src/componentOptions.ts +++ b/packages/core/src/componentOptions.ts @@ -1,4 +1,4 @@ -import { ComponentInstance, MergedComponent } from './component' +import { ComponentInstance, Component } from './component' import { Slots } from './vdom' export type Data = Record @@ -10,7 +10,7 @@ export interface ComponentClassOptions

{ displayName?: string } -export interface ComponentOptions

> +export interface ComponentOptions

> extends ComponentClassOptions { data?(): D render?: (this: This, props: Readonly, slots: Slots, attrs: Data) => any diff --git a/packages/core/src/componentUtils.ts b/packages/core/src/componentUtils.ts index 2950f67c..04a8808b 100644 --- a/packages/core/src/componentUtils.ts +++ b/packages/core/src/componentUtils.ts @@ -39,7 +39,7 @@ export function createComponentInstance( // always pass args in super() currentVNode = vnode currentContextVNode = contextVNode - const instance = (vnode.children = new Component()) as ComponentInstance + const instance = (vnode.children = new Component() as ComponentInstance) // then we finish the initialization by collecting properties set on the // instance initializeState(instance) diff --git a/packages/core/src/h.ts b/packages/core/src/h.ts index c07e11f4..9d4bcb97 100644 --- a/packages/core/src/h.ts +++ b/packages/core/src/h.ts @@ -1,9 +1,5 @@ import { ChildrenFlags } from './flags' -import { - ComponentClass, - FunctionalComponent, - ComponentInstance -} from './component' +import { ComponentClass, FunctionalComponent, Component } from './component' import { ComponentOptions } from './componentOptions' import { VNode, @@ -93,9 +89,9 @@ interface createElement extends VNodeFactories { children?: RawChildrenType | RawSlots ): VNode // class -

(tag: new () => ComponentInstance

, children?: RawChildrenType): VNode +

(tag: new () => Component

, children?: RawChildrenType): VNode

( - tag: new () => ComponentInstance

, + tag: new () => Component

, data?: (P & BuiltInProps & Differ) | null, children?: RawChildrenType | RawSlots ): VNode diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 2feec952..6c2d323c 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -24,12 +24,7 @@ export { createAsyncComponent } from './optional/asyncComponent' export { KeepAlive } from './optional/keepAlive' // flags & types -export { - ComponentType, - ComponentClass, - FunctionalComponent, - ComponentInstance -} from './component' +export { ComponentType, ComponentClass, FunctionalComponent } from './component' export * from './componentOptions' export { VNodeFlags, ChildrenFlags } from './flags' export { VNode, Slots } from './vdom' diff --git a/packages/core/src/vdom.ts b/packages/core/src/vdom.ts index 811f7b26..3db116df 100644 --- a/packages/core/src/vdom.ts +++ b/packages/core/src/vdom.ts @@ -56,6 +56,7 @@ export type VNodeChildren = | ComponentInstance // COMPONENT_STATEFUL | VNode // COMPONENT_FUNCTIONAL | string // TEXT + | null export type Key = string | number