wip(types): improve h typing

This commit is contained in:
Evan You 2018-10-12 13:42:19 -04:00
parent 7e6fdb8cc4
commit 47a2b25a95
4 changed files with 66 additions and 20 deletions

View File

@ -15,13 +15,13 @@ import { initializeComponentInstance } from './componentUtils'
export interface ComponentClass extends ComponentClassOptions { export interface ComponentClass extends ComponentClassOptions {
options?: ComponentOptions options?: ComponentOptions
new <P extends object = {}, D extends object = {}>(): MergedComponent<P, D> new <P = {}, D = {}>(): MergedComponent<P, D>
} }
export type MergedComponent<P, D> = D & P & ComponentInstance<P, D> export type MergedComponent<P, D> = D & P & ComponentInstance<P, D>
export interface FunctionalComponent<P = {}> { export interface FunctionalComponent<P = {}> {
(props: Readonly<P>, slots: Slots, attrs: Data): any (props: P, slots: Slots, attrs: Data): any
pure?: boolean pure?: boolean
props?: ComponentPropsOptions<P> props?: ComponentPropsOptions<P>
displayName?: string displayName?: string

View File

@ -1,5 +1,10 @@
import { ChildrenFlags } from './flags' import { ChildrenFlags } from './flags'
import { ComponentClass, FunctionalComponent } from './component' import {
ComponentClass,
FunctionalComponent,
Component,
ComponentInstance
} from './component'
import { ComponentOptions } from './componentOptions' import { ComponentOptions } from './componentOptions'
import { import {
VNode, VNode,
@ -7,7 +12,9 @@ import {
createComponentVNode, createComponentVNode,
createTextVNode, createTextVNode,
createFragment, createFragment,
createPortal createPortal,
VNodeData,
BuiltInProps
} from './vdom' } from './vdom'
import { isObservable } from '@vue/observer' import { isObservable } from '@vue/observer'
import { warn } from './warning' import { warn } from './warning'
@ -15,7 +22,7 @@ import { warn } from './warning'
export const Fragment = Symbol() export const Fragment = Symbol()
export const Portal = Symbol() export const Portal = Symbol()
type ElementType = export type ElementType =
| string | string
| FunctionalComponent | FunctionalComponent
| ComponentClass | ComponentClass
@ -23,8 +30,11 @@ type ElementType =
| typeof Fragment | typeof Fragment
| typeof Portal | typeof Portal
export interface createElement { type RawChildType = VNode | string | number | boolean | null | undefined
(tag: ElementType, data?: any, children?: any): VNode
export type RawChildrenType = RawChildType | RawChildType[]
interface VNodeFactories {
c: typeof createComponentVNode c: typeof createComponentVNode
e: typeof createElementVNode e: typeof createElementVNode
t: typeof createTextVNode t: typeof createTextVNode
@ -32,6 +42,23 @@ export interface createElement {
p: typeof createPortal p: typeof createPortal
} }
interface createElement {
// element
(tag: string, data?: VNodeData, children?: any): VNode
// functional
<P>(
tag: FunctionalComponent<P>,
data?: P & BuiltInProps | null,
children?: any
): VNode
// stateful
<P, T extends ComponentInstance<P>>(
tag: new () => T & { $props: P },
data?: P & BuiltInProps | null,
children?: any
): VNode
}
export const h = ((tag: ElementType, data?: any, children?: any): VNode => { export const h = ((tag: ElementType, data?: any, children?: any): VNode => {
if ( if (
Array.isArray(data) || Array.isArray(data) ||
@ -111,7 +138,7 @@ export const h = ((tag: ElementType, data?: any, children?: any): VNode => {
ref ref
) )
} }
}) as createElement }) as createElement & VNodeFactories
h.c = createComponentVNode h.c = createComponentVNode
h.e = createElementVNode h.e = createElementVNode

View File

@ -0,0 +1,16 @@
import { ComponentInstance, ComponentType } from '../component'
import { ComponentOptions } from '../componentOptions'
import { RawVNodeChildren, VNodeData } from '../vdom'
export interface Mixin extends ComponentOptions {}
export function applyMixins(Component: ComponentInstance, mixins: Mixin[]) {}
export function h(tag: ComponentType | string, data: RawVNodeChildren): object
export function h(
tag: ComponentType | string,
data: VNodeData,
children: RawVNodeChildren
): object {
return {}
}

View File

@ -6,6 +6,7 @@ import {
import { VNodeFlags, ChildrenFlags } from './flags' import { VNodeFlags, ChildrenFlags } from './flags'
import { createComponentClassFromOptions } from './componentUtils' import { createComponentClassFromOptions } from './componentUtils'
import { normalizeClass, normalizeStyle, handlersRE, EMPTY_OBJ } from './utils' import { normalizeClass, normalizeStyle, handlersRE, EMPTY_OBJ } from './utils'
import { ElementType, RawChildrenType } from './h'
// Vue core is platform agnostic, so we are not using Element for "DOM" nodes. // Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
export interface RenderNode { export interface RenderNode {
@ -40,21 +41,19 @@ export interface MountedVNode extends VNode {
el: RenderNode el: RenderNode
} }
export interface VNodeData { export interface BuiltInProps {
key?: Key | null key?: Key | null
ref?: Ref | null ref?: Ref | null
slots?: Slots | null slots?: RawSlots | null
[key: string]: any
} }
export type VNodeData = Record<string, any> & BuiltInProps
export type VNodeChildren = export type VNodeChildren =
| VNode[] // ELEMENT | PORTAL | VNode[] // ELEMENT | PORTAL
| ComponentInstance // COMPONENT_STATEFUL | ComponentInstance // COMPONENT_STATEFUL
| VNode // COMPONENT_FUNCTIONAL | VNode // COMPONENT_FUNCTIONAL
| string // TEXT | string // TEXT
| null
export type RawVNodeChildren = VNodeChildren | unknown[]
export type Key = string | number export type Key = string | number
@ -66,11 +65,15 @@ export type Slots = Readonly<{
[name: string]: Slot [name: string]: Slot
}> }>
export type RawSlots = {
[name: string]: () => RawChildrenType
}
export function createVNode( export function createVNode(
flags: VNodeFlags, flags: VNodeFlags,
tag: string | FunctionalComponent | ComponentClass | RenderNode | null, tag: string | FunctionalComponent | ComponentClass | RenderNode | null,
data: VNodeData | null, data: VNodeData | null,
children: RawVNodeChildren | null, children: RawChildrenType | null,
childFlags: ChildrenFlags, childFlags: ChildrenFlags,
key: Key | null | undefined, key: Key | null | undefined,
ref: Ref | null | undefined, ref: Ref | null | undefined,
@ -108,7 +111,7 @@ function normalizeClassAndStyle(data: VNodeData) {
export function createElementVNode( export function createElementVNode(
tag: string, tag: string,
data: VNodeData | null, data: VNodeData | null,
children: RawVNodeChildren | null, children: RawChildrenType | null,
childFlags: ChildrenFlags, childFlags: ChildrenFlags,
key?: Key | null, key?: Key | null,
ref?: Ref | null ref?: Ref | null
@ -123,7 +126,7 @@ export function createElementVNode(
export function createComponentVNode( export function createComponentVNode(
comp: any, comp: any,
data: VNodeData | null, data: VNodeData | null,
children: RawVNodeChildren | Slots, children: RawChildrenType | Slots,
childFlags: ChildrenFlags, childFlags: ChildrenFlags,
key?: Key | null, key?: Key | null,
ref?: Ref | null ref?: Ref | null
@ -222,7 +225,7 @@ export function createTextVNode(text: string): VNode {
} }
export function createFragment( export function createFragment(
children: RawVNodeChildren, children: RawChildrenType,
childFlags?: ChildrenFlags, childFlags?: ChildrenFlags,
key?: Key | null key?: Key | null
) { ) {
@ -240,7 +243,7 @@ export function createFragment(
export function createPortal( export function createPortal(
target: RenderNode | string, target: RenderNode | string,
children: RawVNodeChildren, children: RawChildrenType,
childFlags?: ChildrenFlags, childFlags?: ChildrenFlags,
key?: Key | null, key?: Key | null,
ref?: Ref | null ref?: Ref | null
@ -296,7 +299,7 @@ export function cloneVNode(vnode: VNode, extraData?: VNodeData): VNode {
flags, flags,
vnode.tag, vnode.tag,
clonedData, clonedData,
vnode.children, vnode.children as RawChildrenType,
vnode.childFlags, vnode.childFlags,
vnode.key, vnode.key,
vnode.ref, vnode.ref,