diff --git a/packages/core/__tests__/attrsFallthrough.spec.ts b/packages/core/__tests__/attrsFallthrough.spec.ts index c10adb2b..a6df61ce 100644 --- a/packages/core/__tests__/attrsFallthrough.spec.ts +++ b/packages/core/__tests__/attrsFallthrough.spec.ts @@ -6,9 +6,7 @@ describe('attribute fallthrough', () => { const nativeClick = jest.fn() const childUpdated = jest.fn() - class Hello extends Component<{ - count: number - }> { + class Hello extends Component<{}, { count: number }> { data() { return { count: 0 @@ -29,7 +27,7 @@ describe('attribute fallthrough', () => { } } - class Child extends Component<{}, { foo: number }> { + class Child extends Component<{ foo: number }> { updated() { childUpdated() } @@ -75,7 +73,7 @@ describe('attribute fallthrough', () => { const nativeClick = jest.fn() const childUpdated = jest.fn() - class Hello extends Component<{ count: number }> { + class Hello extends Component<{}, { count: number }> { data() { return { count: 0 @@ -96,7 +94,7 @@ describe('attribute fallthrough', () => { } } - class Child extends Component<{}, { foo: number }> { + class Child extends Component<{ foo: number }> { static options = { props: { foo: Number @@ -149,7 +147,7 @@ describe('attribute fallthrough', () => { const childUpdated = jest.fn() const grandChildUpdated = jest.fn() - class Hello extends Component<{ count: number }> { + class Hello extends Component<{}, { count: number }> { data() { return { count: 0 @@ -184,7 +182,7 @@ describe('attribute fallthrough', () => { } } - class GrandChild extends Component<{}, { foo: number }> { + class GrandChild extends Component<{ foo: number }> { static options = { props: { foo: Number diff --git a/packages/core/src/component.ts b/packages/core/src/component.ts index eb35be4d..556ae9b2 100644 --- a/packages/core/src/component.ts +++ b/packages/core/src/component.ts @@ -13,42 +13,40 @@ import { ErrorTypes } from './errorHandling' type Flatten = { [K in keyof T]: T[K] } -export type RenderFunction

= ( - props: P, - slots: Slots, - attrs: Data -) => any - export interface ComponentClass extends Flatten { - new (): D & P & MountedComponent + new

(): MergedComponent } -export interface FunctionalComponent

extends RenderFunction

{ +export type MergedComponent = D & P & MountedComponent + +export interface FunctionalComponent

{ + (props: Readonly

, slots: Slots, attrs: Data): any pure?: boolean props?: ComponentPropsOptions

inheritAttrs?: boolean + displayName?: string } export type ComponentType = ComponentClass | FunctionalComponent // this interface is merged with the class type // to represent a mounted component -export interface MountedComponent extends InternalComponent { +export interface MountedComponent

extends InternalComponent { $vnode: MountedVNode $data: D - $props: P + $props: Readonly

$attrs: Data $computed: Data $slots: Slots $root: MountedComponent $children: MountedComponent[] - $options: ComponentOptions + $options: ComponentOptions - render(props: P, slots: Slots, attrs: Data): any + data?(): Partial + render(props: Readonly

, slots: Slots, attrs: Data): any renderError?(e: Error): any renderTracked?(e: DebuggerEvent): void renderTriggered?(e: DebuggerEvent): void - data?(): Partial beforeCreate?(): void created?(): void beforeMount?(): void @@ -120,16 +118,15 @@ class InternalComponent { } $watch( - this: MountedComponent, keyOrFn: string | (() => any), cb: (newValue: any, oldValue: any) => void, options?: WatchOptions ) { - return setupWatcher(this, keyOrFn, cb, options) + return setupWatcher(this as any, keyOrFn, cb, options) } // eventEmitter interface - $on(this: MountedComponent, event: string, fn: Function): MountedComponent { + $on(event: string, fn: Function): this { if (Array.isArray(event)) { for (let i = 0; i < event.length; i++) { this.$on(event[i], fn) @@ -141,7 +138,7 @@ class InternalComponent { return this } - $once(this: MountedComponent, event: string, fn: Function): MountedComponent { + $once(event: string, fn: Function): this { const onceFn = (...args: any[]) => { this.$off(event, onceFn) fn.apply(this, args) @@ -150,11 +147,7 @@ class InternalComponent { return this.$on(event, onceFn) } - $off( - this: MountedComponent, - event?: string, - fn?: Function - ): MountedComponent { + $off(event?: string, fn?: Function): this { if (this._events) { if (!event && !fn) { this._events = null @@ -180,11 +173,7 @@ class InternalComponent { return this } - $emit( - this: MountedComponent, - name: string, - ...payload: any[] - ): MountedComponent { + $emit(name: string, ...payload: any[]): this { const parentData = (this.$parentVNode && this.$parentVNode.data) || EMPTY_OBJ const parentListener = diff --git a/packages/core/src/componentOptions.ts b/packages/core/src/componentOptions.ts index 5723d10e..ab8c5194 100644 --- a/packages/core/src/componentOptions.ts +++ b/packages/core/src/componentOptions.ts @@ -1,14 +1,22 @@ -import { MountedComponent, RenderFunction } from './component' +import { MergedComponent, MountedComponent } from './component' +import { Slots } from './vdom' export type Data = Record -export interface ComponentOptions { - data?: () => Partial +export interface ComponentOptions< + P = {}, + D = {}, + M = {}, + C = {}, + This = MergedComponent & M & C +> { + data?: (this: This) => Partial props?: ComponentPropsOptions

- computed?: ComponentComputedOptions - watch?: ComponentWatchOptions - render?: RenderFunction

+ computed?: ComponentComputedOptions + watch?: ComponentWatchOptions + render?: (this: This, props: Readonly

, slots: Slots, attrs: Data) => any inheritAttrs?: boolean + displayName?: string // TODO other options readonly [key: string]: any } @@ -30,24 +38,28 @@ export interface PropOptions { validator?(value: T): boolean } -export interface ComponentComputedOptions { - [key: string]: (this: MountedComponent & D & P, c: any) => any +export interface ComponentComputedOptions { + [key: string]: (this: This, c: any) => any } -export interface ComponentWatchOptions { - [key: string]: ComponentWatchOption & D & P> +export interface ComponentWatchOptions { + [key: string]: ComponentWatchOption } -export type ComponentWatchOption = - | WatchHandler - | WatchHandler[] - | WatchOptionsWithHandler +export type ComponentWatchOption = + | WatchHandler + | WatchHandler[] + | WatchOptionsWithHandler | string -export type WatchHandler = (this: C, val: any, oldVal: any) => void +export type WatchHandler = ( + this: This, + val: any, + oldVal: any +) => void -export interface WatchOptionsWithHandler extends WatchOptions { - handler: WatchHandler +export interface WatchOptionsWithHandler extends WatchOptions { + handler: WatchHandler } export interface WatchOptions { diff --git a/packages/core/src/optional/asyncComponent.ts b/packages/core/src/optional/asyncComponent.ts index 1a60b49e..5b5a2c70 100644 --- a/packages/core/src/optional/asyncComponent.ts +++ b/packages/core/src/optional/asyncComponent.ts @@ -40,7 +40,7 @@ export function createAsyncComponent( error: errorComp } = options - return class AsyncContainer extends Component { + return class AsyncContainer extends Component<{}, AsyncContainerData> { data() { return { comp: null, diff --git a/packages/core/src/optional/context.ts b/packages/core/src/optional/context.ts index f8d688d5..a260370d 100644 --- a/packages/core/src/optional/context.ts +++ b/packages/core/src/optional/context.ts @@ -8,7 +8,7 @@ interface ProviderProps { value: any } -export class Provide extends Component<{}, ProviderProps> { +export class Provide extends Component { updateValue() { // TS doesn't allow symbol as index :/ // https://github.com/Microsoft/TypeScript/issues/24587 diff --git a/packages/core/src/optional/keepAlive.ts b/packages/core/src/optional/keepAlive.ts index 00d1aa18..1525b37d 100644 --- a/packages/core/src/optional/keepAlive.ts +++ b/packages/core/src/optional/keepAlive.ts @@ -15,7 +15,7 @@ type Cache = Map export const KeepAliveSymbol = Symbol() -export class KeepAlive extends Component<{}, KeepAliveProps> { +export class KeepAlive extends Component { cache: Cache = new Map() keys: Set = new Set() diff --git a/packages/core/src/vdom.ts b/packages/core/src/vdom.ts index 9f3185c0..14b85f74 100644 --- a/packages/core/src/vdom.ts +++ b/packages/core/src/vdom.ts @@ -27,8 +27,9 @@ export interface VNode { slots: Slots | null // only on mounted nodes el: RenderNode | null - // only on mounted component root nodes - // points to component node in parent tree + // only on mounted component nodes that is also a root node (HOCs) + // points to parent component's placeholder vnode + // this is used to update vnode.el for nested HOCs. parentVNode: VNode | null } @@ -56,12 +57,12 @@ export type Key = string | number export type Ref = (t: RenderNode | MountedComponent | null) => void -export interface Slots { - [name: string]: Slot -} - export type Slot = (...args: any[]) => VNode[] +export type Slots = Readonly<{ + [name: string]: Slot +}> + export function createVNode( flags: VNodeFlags, tag: string | FunctionalComponent | ComponentClass | RenderNode | null, diff --git a/packages/renderer-dom/src/components/transition-group.ts b/packages/renderer-dom/src/components/transition-group.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/renderer-dom/src/components/transition.ts b/packages/renderer-dom/src/components/transition.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/vue/__tests__/compat.spec.ts b/packages/vue/__tests__/compat.spec.ts index b1aa63c2..580e202d 100644 --- a/packages/vue/__tests__/compat.spec.ts +++ b/packages/vue/__tests__/compat.spec.ts @@ -7,7 +7,7 @@ describe('2.x compat build', async () => { const root = document.createElement('div') document.body.appendChild(root) - const instance = new Vue({ + const instance = new Vue({ data() { return { count: 0 } }, diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index a7dea494..53b9e2da 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -6,13 +6,19 @@ import { ComponentOptions, createComponentInstance } from '@vue/renderer-dom' +import { MergedComponent } from '../../core/src/component' -class Vue extends Component { +class Vue< + P extends object = {}, + D extends object = {}, + M extends object = {}, + C extends object = {} +> extends Component { static h = h static render = render static nextTick = nextTick - constructor(options: ComponentOptions & { el?: any }) { + constructor(options: ComponentOptions & { el?: any }) { super() if (!options) { return @@ -43,5 +49,9 @@ class Vue extends Component { } } +interface Vue { + $mount(el: any): MergedComponent & M & C +} + export default Vue export * from '@vue/renderer-dom'