types: improve createElement typing
This commit is contained in:
parent
93d724382e
commit
5257b366fd
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -22,7 +22,6 @@
|
|||||||
"rust",
|
"rust",
|
||||||
"scss",
|
"scss",
|
||||||
"text",
|
"text",
|
||||||
"typescriptreact",
|
|
||||||
"yml"
|
"yml"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,8 @@ describe('attribute fallthrough', () => {
|
|||||||
const click = jest.fn()
|
const click = jest.fn()
|
||||||
const childUpdated = jest.fn()
|
const childUpdated = jest.fn()
|
||||||
|
|
||||||
class Hello extends Component<{}, { count: number }> {
|
class Hello extends Component {
|
||||||
data() {
|
count: number = 0
|
||||||
return {
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inc() {
|
inc() {
|
||||||
this.count++
|
this.count++
|
||||||
click()
|
click()
|
||||||
@ -27,7 +23,7 @@ describe('attribute fallthrough', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Child extends Component {
|
class Child extends Component<{ [key: string]: any }> {
|
||||||
updated() {
|
updated() {
|
||||||
childUpdated()
|
childUpdated()
|
||||||
}
|
}
|
||||||
@ -73,19 +69,15 @@ describe('attribute fallthrough', () => {
|
|||||||
const click = jest.fn()
|
const click = jest.fn()
|
||||||
const childUpdated = jest.fn()
|
const childUpdated = jest.fn()
|
||||||
|
|
||||||
class Hello extends Component<{}, { count: number }> {
|
class Hello extends Component {
|
||||||
data() {
|
count = 0
|
||||||
return {
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inc() {
|
inc() {
|
||||||
this.count++
|
this.count++
|
||||||
click()
|
click()
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return h(Child, {
|
return h(Child, {
|
||||||
foo: 1,
|
foo: 123,
|
||||||
id: 'test',
|
id: 'test',
|
||||||
class: 'c' + this.count,
|
class: 'c' + this.count,
|
||||||
style: { color: this.count ? 'red' : 'green' },
|
style: { color: this.count ? 'red' : 'green' },
|
||||||
@ -94,7 +86,7 @@ describe('attribute fallthrough', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Child extends Component<{ foo: number }> {
|
class Child extends Component<{ [key: string]: any; foo: number }> {
|
||||||
static props = {
|
static props = {
|
||||||
foo: Number
|
foo: Number
|
||||||
}
|
}
|
||||||
@ -148,12 +140,8 @@ describe('attribute fallthrough', () => {
|
|||||||
const childUpdated = jest.fn()
|
const childUpdated = jest.fn()
|
||||||
const grandChildUpdated = jest.fn()
|
const grandChildUpdated = jest.fn()
|
||||||
|
|
||||||
class Hello extends Component<{}, { count: number }> {
|
class Hello extends Component {
|
||||||
data() {
|
count = 0
|
||||||
return {
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inc() {
|
inc() {
|
||||||
this.count++
|
this.count++
|
||||||
click()
|
click()
|
||||||
@ -169,7 +157,7 @@ describe('attribute fallthrough', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Child extends Component {
|
class Child extends Component<{ [key: string]: any; foo: number }> {
|
||||||
updated() {
|
updated() {
|
||||||
childUpdated()
|
childUpdated()
|
||||||
}
|
}
|
||||||
@ -178,7 +166,7 @@ describe('attribute fallthrough', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GrandChild extends Component<{ foo: number }> {
|
class GrandChild extends Component<{ [key: string]: any; foo: number }> {
|
||||||
static props = {
|
static props = {
|
||||||
foo: Number
|
foo: Number
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@ import { nextTick } from '@vue/scheduler'
|
|||||||
import { ErrorTypes } from './errorHandling'
|
import { ErrorTypes } from './errorHandling'
|
||||||
import { initializeComponentInstance } from './componentUtils'
|
import { initializeComponentInstance } from './componentUtils'
|
||||||
|
|
||||||
export interface ComponentClass extends ComponentClassOptions {
|
export interface ComponentClass<P = {}> extends ComponentClassOptions {
|
||||||
options?: ComponentOptions
|
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>
|
export type MergedComponent<P, D> = D & P & ComponentInstance<P, D>
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { ComponentInstance } from './component'
|
import { ComponentInstance, MergedComponent } from './component'
|
||||||
import { Slots } from './vdom'
|
import { Slots } from './vdom'
|
||||||
|
|
||||||
export type Data = Record<string, any>
|
export type Data = Record<string, any>
|
||||||
|
|
||||||
export interface ComponentClassOptions<This = ComponentInstance> {
|
export interface ComponentClassOptions<P = {}, This = ComponentInstance> {
|
||||||
props?: ComponentPropsOptions
|
props?: ComponentPropsOptions<P>
|
||||||
computed?: ComponentComputedOptions<This>
|
computed?: ComponentComputedOptions<This>
|
||||||
watch?: ComponentWatchOptions<This>
|
watch?: ComponentWatchOptions<This>
|
||||||
displayName?: string
|
displayName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentOptions<This = ComponentInstance>
|
export interface ComponentOptions<P = {}, D = {}, This = MergedComponent<P, D>>
|
||||||
extends ComponentClassOptions<This> {
|
extends ComponentClassOptions<P, This> {
|
||||||
data?(): object
|
data?(): D
|
||||||
render?: (this: This, props: Readonly<Data>, slots: Slots, attrs: Data) => any
|
render?: (this: This, props: Readonly<Data>, slots: Slots, attrs: Data) => any
|
||||||
// TODO other options
|
// TODO other options
|
||||||
readonly [key: string]: any
|
readonly [key: string]: any
|
||||||
|
@ -2,7 +2,6 @@ import { ChildrenFlags } from './flags'
|
|||||||
import {
|
import {
|
||||||
ComponentClass,
|
ComponentClass,
|
||||||
FunctionalComponent,
|
FunctionalComponent,
|
||||||
Component,
|
|
||||||
ComponentInstance
|
ComponentInstance
|
||||||
} from './component'
|
} from './component'
|
||||||
import { ComponentOptions } from './componentOptions'
|
import { ComponentOptions } from './componentOptions'
|
||||||
@ -14,7 +13,8 @@ import {
|
|||||||
createFragment,
|
createFragment,
|
||||||
createPortal,
|
createPortal,
|
||||||
VNodeData,
|
VNodeData,
|
||||||
BuiltInProps
|
BuiltInProps,
|
||||||
|
Key
|
||||||
} from './vdom'
|
} from './vdom'
|
||||||
import { isObservable } from '@vue/observer'
|
import { isObservable } from '@vue/observer'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
@ -22,6 +22,14 @@ import { warn } from './warning'
|
|||||||
export const Fragment = Symbol()
|
export const Fragment = Symbol()
|
||||||
export const Portal = 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 =
|
export type ElementType =
|
||||||
| string
|
| string
|
||||||
| FunctionalComponent
|
| FunctionalComponent
|
||||||
@ -30,10 +38,6 @@ export type ElementType =
|
|||||||
| typeof Fragment
|
| typeof Fragment
|
||||||
| typeof Portal
|
| typeof Portal
|
||||||
|
|
||||||
type RawChildType = VNode | string | number | boolean | null | undefined
|
|
||||||
|
|
||||||
export type RawChildrenType = RawChildType | RawChildType[]
|
|
||||||
|
|
||||||
interface VNodeFactories {
|
interface VNodeFactories {
|
||||||
c: typeof createComponentVNode
|
c: typeof createComponentVNode
|
||||||
e: typeof createElementVNode
|
e: typeof createElementVNode
|
||||||
@ -42,20 +46,60 @@ interface VNodeFactories {
|
|||||||
p: typeof createPortal
|
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
|
// 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
|
// functional
|
||||||
<P>(
|
<P>(
|
||||||
tag: FunctionalComponent<P>,
|
tag: FunctionalComponent<P>,
|
||||||
data?: P & BuiltInProps | null,
|
data?: (P & BuiltInProps & Differ) | null,
|
||||||
children?: any
|
children?: RawChildrenType | RawSlots
|
||||||
): VNode
|
): VNode
|
||||||
// stateful
|
<P>(tag: FunctionalComponent<P>, children?: RawChildrenType): VNode
|
||||||
|
// class
|
||||||
<P, T extends ComponentInstance<P>>(
|
<P, T extends ComponentInstance<P>>(
|
||||||
tag: new () => T & { $props: P },
|
tag: new () => T & { $props: P },
|
||||||
data?: P & BuiltInProps | null,
|
data?: (P & BuiltInProps & Differ) | null,
|
||||||
children?: any
|
children?: RawChildrenType | RawSlots
|
||||||
|
): VNode
|
||||||
|
<P, T extends ComponentInstance<P>>(
|
||||||
|
tag: new () => T & { $props: P },
|
||||||
|
children?: RawChildrenType
|
||||||
): VNode
|
): VNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +182,7 @@ export const h = ((tag: ElementType, data?: any, children?: any): VNode => {
|
|||||||
ref
|
ref
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}) as createElement & VNodeFactories
|
}) as createElement
|
||||||
|
|
||||||
h.c = createComponentVNode
|
h.c = createComponentVNode
|
||||||
h.e = createElementVNode
|
h.e = createElementVNode
|
||||||
|
@ -1,16 +1,6 @@
|
|||||||
import { ComponentInstance, ComponentType } from '../component'
|
import { ComponentInstance } from '../component'
|
||||||
import { ComponentOptions } from '../componentOptions'
|
import { ComponentOptions } from '../componentOptions'
|
||||||
import { RawVNodeChildren, VNodeData } from '../vdom'
|
|
||||||
|
|
||||||
export interface Mixin extends ComponentOptions {}
|
export interface Mixin extends ComponentOptions {}
|
||||||
|
|
||||||
export function applyMixins(Component: ComponentInstance, mixins: Mixin[]) {}
|
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 {}
|
|
||||||
}
|
|
||||||
|
@ -6,7 +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'
|
import { RawChildrenType, RawSlots } 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 {
|
||||||
@ -47,7 +47,9 @@ export interface BuiltInProps {
|
|||||||
slots?: RawSlots | null
|
slots?: RawSlots | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VNodeData = Record<string, any> & BuiltInProps
|
export type VNodeData = {
|
||||||
|
[key: string]: any
|
||||||
|
} & BuiltInProps
|
||||||
|
|
||||||
export type VNodeChildren =
|
export type VNodeChildren =
|
||||||
| VNode[] // ELEMENT | PORTAL
|
| VNode[] // ELEMENT | PORTAL
|
||||||
@ -65,10 +67,6 @@ 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,
|
||||||
|
@ -7,8 +7,9 @@ import { patchEvent } from './modules/events'
|
|||||||
|
|
||||||
export const onRE = /^on/
|
export const onRE = /^on/
|
||||||
|
|
||||||
// value, checked, selected & muted are always patched as properties
|
// value, checked, selected & muted
|
||||||
const domPropsRE = /^domProps|^(?: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(
|
export function patchData(
|
||||||
el: Element,
|
el: Element,
|
||||||
|
Loading…
Reference in New Issue
Block a user