refactor: types refactor

This commit is contained in:
Evan You 2018-10-08 18:09:13 -04:00
parent ba918b5afe
commit d22b71b27e
11 changed files with 74 additions and 64 deletions

View File

@ -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

View File

@ -13,42 +13,40 @@ import { ErrorTypes } from './errorHandling'
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
@ -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 =

View File

@ -1,14 +1,22 @@
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
}
@ -30,24 +38,28 @@ export interface PropOptions<T = 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 {

View File

@ -40,7 +40,7 @@ export function createAsyncComponent(
error: errorComp
} = options
return class AsyncContainer extends Component<AsyncContainerData> {
return class AsyncContainer extends Component<{}, AsyncContainerData> {
data() {
return {
comp: null,

View File

@ -8,7 +8,7 @@ interface ProviderProps {
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

View File

@ -15,7 +15,7 @@ type Cache = Map<CacheKey, VNode>
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()

View File

@ -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,

View File

@ -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<any>({
data() {
return { count: 0 }
},

View File

@ -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<P, D, M, C> & { el?: any }) {
super()
if (!options) {
return
@ -43,5 +49,9 @@ class Vue extends Component {
}
}
interface Vue<P, D, M, C> {
$mount(el: any): MergedComponent<P, D> & M & C
}
export default Vue
export * from '@vue/renderer-dom'