Skip to content

Commit

Permalink
types: improve createElement typing
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Oct 12, 2018
1 parent 93d7243 commit 5257b36
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 65 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"rust",
"scss",
"text",
"typescriptreact",
"yml"
]
}
34 changes: 11 additions & 23 deletions packages/core/__tests__/attrsFallthrough.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ describe('attribute fallthrough', () => {
const click = jest.fn()
const childUpdated = jest.fn()

class Hello extends Component<{}, { count: number }> {
data() {
return {
count: 0
}
}
class Hello extends Component {
count: number = 0
inc() {
this.count++
click()
Expand All @@ -27,7 +23,7 @@ describe('attribute fallthrough', () => {
}
}

class Child extends Component {
class Child extends Component<{ [key: string]: any }> {
updated() {
childUpdated()
}
Expand Down Expand Up @@ -73,19 +69,15 @@ describe('attribute fallthrough', () => {
const click = jest.fn()
const childUpdated = jest.fn()

class Hello extends Component<{}, { count: number }> {
data() {
return {
count: 0
}
}
class Hello extends Component {
count = 0
inc() {
this.count++
click()
}
render() {
return h(Child, {
foo: 1,
foo: 123,
id: 'test',
class: 'c' + this.count,
style: { color: this.count ? 'red' : 'green' },
Expand All @@ -94,7 +86,7 @@ describe('attribute fallthrough', () => {
}
}

class Child extends Component<{ foo: number }> {
class Child extends Component<{ [key: string]: any; foo: number }> {
static props = {
foo: Number
}
Expand Down Expand Up @@ -148,12 +140,8 @@ describe('attribute fallthrough', () => {
const childUpdated = jest.fn()
const grandChildUpdated = jest.fn()

class Hello extends Component<{}, { count: number }> {
data() {
return {
count: 0
}
}
class Hello extends Component {
count = 0
inc() {
this.count++
click()
Expand All @@ -169,7 +157,7 @@ describe('attribute fallthrough', () => {
}
}

class Child extends Component {
class Child extends Component<{ [key: string]: any; foo: number }> {
updated() {
childUpdated()
}
Expand All @@ -178,7 +166,7 @@ describe('attribute fallthrough', () => {
}
}

class GrandChild extends Component<{ foo: number }> {
class GrandChild extends Component<{ [key: string]: any; foo: number }> {
static props = {
foo: Number
}
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { nextTick } from '@vue/scheduler'
import { ErrorTypes } from './errorHandling'
import { initializeComponentInstance } from './componentUtils'

export interface ComponentClass extends ComponentClassOptions {
export interface ComponentClass<P = {}> extends ComponentClassOptions {
options?: ComponentOptions
new <P = {}, D = {}>(): MergedComponent<P, D>
new <P = {}, D = {}>(props?: P): MergedComponent<P, D>
}

export type MergedComponent<P, D> = D & P & ComponentInstance<P, D>
Expand Down
12 changes: 6 additions & 6 deletions packages/core/src/componentOptions.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { ComponentInstance } from './component'
import { ComponentInstance, MergedComponent } from './component'
import { Slots } from './vdom'

export type Data = Record<string, any>

export interface ComponentClassOptions<This = ComponentInstance> {
props?: ComponentPropsOptions
export interface ComponentClassOptions<P = {}, This = ComponentInstance> {
props?: ComponentPropsOptions<P>
computed?: ComponentComputedOptions<This>
watch?: ComponentWatchOptions<This>
displayName?: string
}

export interface ComponentOptions<This = ComponentInstance>
extends ComponentClassOptions<This> {
data?(): object
export interface ComponentOptions<P = {}, D = {}, This = MergedComponent<P, D>>
extends ComponentClassOptions<P, This> {
data?(): D
render?: (this: This, props: Readonly<Data>, slots: Slots, attrs: Data) => any
// TODO other options
readonly [key: string]: any
Expand Down
72 changes: 58 additions & 14 deletions packages/core/src/h.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ChildrenFlags } from './flags'
import {
ComponentClass,
FunctionalComponent,
Component,
ComponentInstance
} from './component'
import { ComponentOptions } from './componentOptions'
Expand All @@ -14,14 +13,23 @@ import {
createFragment,
createPortal,
VNodeData,
BuiltInProps
BuiltInProps,
Key
} from './vdom'
import { isObservable } from '@vue/observer'
import { warn } from './warning'

export const Fragment = Symbol()
export const Portal = Symbol()

type RawChildType = VNode | string | number | boolean | null | undefined

export type RawSlots = {
[name: string]: () => RawChildrenType
}

export type RawChildrenType = RawChildType | RawChildType[]

export type ElementType =
| string
| FunctionalComponent
Expand All @@ -30,10 +38,6 @@ export type ElementType =
| typeof Fragment
| typeof Portal

type RawChildType = VNode | string | number | boolean | null | undefined

export type RawChildrenType = RawChildType | RawChildType[]

interface VNodeFactories {
c: typeof createComponentVNode
e: typeof createElementVNode
Expand All @@ -42,20 +46,60 @@ interface VNodeFactories {
p: typeof createPortal
}

interface createElement {
// This is used to differentiate the data object from
// vnodes and arrays
type Differ = { _isVNode?: never; [Symbol.iterator]?: never }

type OptionsComponent<P> =
| (ComponentOptions<P> & { template: string })
| (ComponentOptions<P> & { render: Function })

interface createElement extends VNodeFactories {
// element
(tag: string, data?: VNodeData, children?: any): VNode
(
tag: string,
// TODO support native element properties
data?: VNodeData & Differ | null,
children?: RawChildrenType | RawSlots
): VNode
(tag: string, children?: RawChildrenType): VNode
// fragment
(
tag: typeof Fragment,
data?: ({ key?: Key } & Differ) | null,
children?: RawChildrenType | RawSlots
): VNode
(tag: typeof Fragment, children?: RawChildrenType): VNode
// portal
(
tag: typeof Portal,
data?: ({ target: any } & BuiltInProps & Differ) | null,
children?: RawChildrenType | RawSlots
): VNode
(tag: typeof Portal, children?: RawChildrenType): VNode
// object
<P>(
tag: OptionsComponent<P>,
data?: (P & BuiltInProps & Differ) | null,
children?: RawChildrenType | RawSlots
): VNode
<P>(tag: OptionsComponent<P>, children?: RawChildrenType): VNode
// functional
<P>(
tag: FunctionalComponent<P>,
data?: P & BuiltInProps | null,
children?: any
data?: (P & BuiltInProps & Differ) | null,
children?: RawChildrenType | RawSlots
): VNode
<P>(tag: FunctionalComponent<P>, children?: RawChildrenType): VNode
// class
<P, T extends ComponentInstance<P>>(
tag: new () => T & { $props: P },
data?: (P & BuiltInProps & Differ) | null,
children?: RawChildrenType | RawSlots
): VNode
// stateful
<P, T extends ComponentInstance<P>>(
tag: new () => T & { $props: P },
data?: P & BuiltInProps | null,
children?: any
children?: RawChildrenType
): VNode
}

Expand Down Expand Up @@ -138,7 +182,7 @@ export const h = ((tag: ElementType, data?: any, children?: any): VNode => {
ref
)
}
}) as createElement & VNodeFactories
}) as createElement

h.c = createComponentVNode
h.e = createElementVNode
Expand Down
12 changes: 1 addition & 11 deletions packages/core/src/optional/mixin.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import { ComponentInstance, ComponentType } from '../component'
import { ComponentInstance } 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 {}
}
10 changes: 4 additions & 6 deletions packages/core/src/vdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { VNodeFlags, ChildrenFlags } from './flags'
import { createComponentClassFromOptions } from './componentUtils'
import { normalizeClass, normalizeStyle, handlersRE, EMPTY_OBJ } from './utils'
import { ElementType, RawChildrenType } from './h'
import { RawChildrenType, RawSlots } from './h'

// Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
export interface RenderNode {
Expand Down Expand Up @@ -47,7 +47,9 @@ export interface BuiltInProps {
slots?: RawSlots | null
}

export type VNodeData = Record<string, any> & BuiltInProps
export type VNodeData = {
[key: string]: any
} & BuiltInProps

export type VNodeChildren =
| VNode[] // ELEMENT | PORTAL
Expand All @@ -65,10 +67,6 @@ export type Slots = Readonly<{
[name: string]: Slot
}>

export type RawSlots = {
[name: string]: () => RawChildrenType
}

export function createVNode(
flags: VNodeFlags,
tag: string | FunctionalComponent | ComponentClass | RenderNode | null,
Expand Down
5 changes: 3 additions & 2 deletions packages/renderer-dom/src/patchData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { patchEvent } from './modules/events'

export const onRE = /^on/

// value, checked, selected & muted are always patched as properties
const domPropsRE = /^domProps|^(?:value|checked|selected|muted)$/
// value, checked, selected & muted
// plus anything with upperCase letter in it are always patched as properties
const domPropsRE = /\W|^(?:value|checked|selected|muted)$/

export function patchData(
el: Element,
Expand Down

0 comments on commit 5257b36

Please sign in to comment.