const nativeClick = jest.fn()
const childUpdated = jest.fn()
- class Hello extends Component<{
- count: number
- }> {
+ class Hello extends Component<{}, { count: number }> {
data() {
return {
count: 0
}
}
- class Child extends Component<{}, { foo: number }> {
+ class Child extends Component<{ foo: number }> {
updated() {
childUpdated()
}
const nativeClick = jest.fn()
const childUpdated = jest.fn()
- class Hello extends Component<{ count: number }> {
+ class Hello extends Component<{}, { count: number }> {
data() {
return {
count: 0
}
}
- class Child extends Component<{}, { foo: number }> {
+ class Child extends Component<{ foo: number }> {
static options = {
props: {
foo: Number
const childUpdated = jest.fn()
const grandChildUpdated = jest.fn()
- class Hello extends Component<{ count: number }> {
+ class Hello extends Component<{}, { count: number }> {
data() {
return {
count: 0
}
}
- class GrandChild extends Component<{}, { foo: number }> {
+ class GrandChild extends Component<{ foo: number }> {
static options = {
props: {
foo: Number
type Flatten<T> = { [K in keyof T]: T[K] }
-export type RenderFunction<P = {}> = (
- props: P,
- slots: Slots,
- attrs: Data
-) => any
-
export interface ComponentClass extends Flatten<typeof InternalComponent> {
- new <D = {}, P = {}>(): D & P & MountedComponent<D, P>
+ new <P extends object = {}, D extends object = {}>(): MergedComponent<P, D>
}
-export interface FunctionalComponent<P = {}> extends RenderFunction<P> {
+export type MergedComponent<P, D> = D & P & MountedComponent<P, D>
+
+export interface FunctionalComponent<P = {}> {
+ (props: Readonly<P>, slots: Slots, attrs: Data): any
pure?: boolean
props?: ComponentPropsOptions<P>
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<D = {}, P = {}> extends InternalComponent {
+export interface MountedComponent<P = {}, D = {}> extends InternalComponent {
$vnode: MountedVNode
$data: D
- $props: P
+ $props: Readonly<P>
$attrs: Data
$computed: Data
$slots: Slots
$root: MountedComponent
$children: MountedComponent[]
- $options: ComponentOptions<D, P>
+ $options: ComponentOptions<P, D>
- render(props: P, slots: Slots, attrs: Data): any
+ data?(): Partial<D>
+ render(props: Readonly<P>, slots: Slots, attrs: Data): any
renderError?(e: Error): any
renderTracked?(e: DebuggerEvent): void
renderTriggered?(e: DebuggerEvent): void
- data?(): Partial<D>
beforeCreate?(): void
created?(): void
beforeMount?(): void
}
$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)
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)
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
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 =
-import { MountedComponent, RenderFunction } from './component'
+import { MergedComponent, MountedComponent } from './component'
+import { Slots } from './vdom'
export type Data = Record<string, any>
-export interface ComponentOptions<D = Data, P = Data> {
- data?: () => Partial<D>
+export interface ComponentOptions<
+ P = {},
+ D = {},
+ M = {},
+ C = {},
+ This = MergedComponent<P, D> & M & C
+> {
+ data?: (this: This) => Partial<D>
props?: ComponentPropsOptions<P>
- computed?: ComponentComputedOptions<D, P>
- watch?: ComponentWatchOptions<D, P>
- render?: RenderFunction<P>
+ computed?: ComponentComputedOptions<This>
+ watch?: ComponentWatchOptions<This>
+ render?: (this: This, props: Readonly<P>, slots: Slots, attrs: Data) => any
inheritAttrs?: boolean
+ displayName?: string
// TODO other options
readonly [key: string]: any
}
validator?(value: T): boolean
}
-export interface ComponentComputedOptions<D = Data, P = Data> {
- [key: string]: (this: MountedComponent<D, P> & D & P, c: any) => any
+export interface ComponentComputedOptions<This = MountedComponent> {
+ [key: string]: (this: This, c: any) => any
}
-export interface ComponentWatchOptions<D = Data, P = Data> {
- [key: string]: ComponentWatchOption<MountedComponent<D, P> & D & P>
+export interface ComponentWatchOptions<This = MountedComponent> {
+ [key: string]: ComponentWatchOption<This>
}
-export type ComponentWatchOption<C = any> =
- | WatchHandler<C>
- | WatchHandler<C>[]
- | WatchOptionsWithHandler<C>
+export type ComponentWatchOption<This = MountedComponent> =
+ | WatchHandler<This>
+ | WatchHandler<This>[]
+ | WatchOptionsWithHandler<This>
| string
-export type WatchHandler<C = any> = (this: C, val: any, oldVal: any) => void
+export type WatchHandler<This = any> = (
+ this: This,
+ val: any,
+ oldVal: any
+) => void
-export interface WatchOptionsWithHandler<C = any> extends WatchOptions {
- handler: WatchHandler<C>
+export interface WatchOptionsWithHandler<This = any> extends WatchOptions {
+ handler: WatchHandler<This>
}
export interface WatchOptions {
error: errorComp
} = options
- return class AsyncContainer extends Component<AsyncContainerData> {
+ return class AsyncContainer extends Component<{}, AsyncContainerData> {
data() {
return {
comp: null,
value: any
}
-export class Provide extends Component<{}, ProviderProps> {
+export class Provide extends Component<ProviderProps> {
updateValue() {
// TS doesn't allow symbol as index :/
// https://github.com/Microsoft/TypeScript/issues/24587
export const KeepAliveSymbol = Symbol()
-export class KeepAlive extends Component<{}, KeepAliveProps> {
+export class KeepAlive extends Component<KeepAliveProps> {
cache: Cache = new Map()
keys: Set<CacheKey> = new Set()
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
}
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,
const root = document.createElement('div')
document.body.appendChild(root)
- const instance = new Vue({
+ const instance = new Vue<any>({
data() {
return { count: 0 }
},
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<P, D, M, C> & { el?: any }) {
super()
if (!options) {
return
}
}
+interface Vue<P, D, M, C> {
+ $mount(el: any): MergedComponent<P, D> & M & C
+}
+
export default Vue
export * from '@vue/renderer-dom'