rework type annotation strategy: use interface instead

This commit is contained in:
Evan You 2016-05-13 18:30:04 -04:00
parent 6dc2662b40
commit 1b7ab89a5d
21 changed files with 333 additions and 300 deletions

View File

@ -8,6 +8,7 @@
[include]
[libs]
flow
[options]
module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1'

116
flow/declarations.js Normal file
View File

@ -0,0 +1,116 @@
import type { Config } from '../src/core/config'
import type VNode from '../src/core/vdom/vnode'
import type Watcher from '../src/core/observer/watcher'
declare interface Component {
// constructor information
static cid: number;
static options: Object;
// extend
static extend: (options: Object) => Function;
// assets
static directive: (id: string, def?: Function | Object) => Function | Object | void;
static component: (id: string, def?: Class<Component> | Object) => Class<Component>;
static transition: (id: string, def?: Object) => Object | void;
static filter: (id: string, def?: Function) => Function | void;
// public properties
$el: Element | void;
$data: Object;
$options: Object;
$parent: Component | void;
$root: Component;
$children: Array<Component>;
$refs: { [key: string]: Component | Element | Array<Component | Element> | void };
$slots: { [key: string]: Array<VNode> };
$isServer: boolean;
// public methods
$mount: (el?: Element | string) => Component;
$forceUpdate: () => void;
$destroy: () => void;
$watch: (expOrFn: string | Function, cb: Function, options?: Object) => Function;
$on: (event: string, fn: Function) => Component;
$once: (event: string, fn: Function) => Component;
$off: (event?: string, fn?: Function) => Component;
$emit: (event: string, ...args: Array<any>) => Component;
$nextTick: (fn: Function) => void;
$createElement: (
tag?: string | Component,
data?: Object,
children?: Array<?VNode> | string,
namespace?: string
) => VNode;
// private properties
_uid: number;
_isVue: true;
_renderProxy: Component;
_watcher: Watcher;
_watchers: Array<Watcher>;
_data: Object;
_events: Object;
_isMounted: boolean;
_isDestroyed: boolean;
_isBeingDestroyed: boolean;
_vnode: ?VNode;
_staticTrees: ?Array<VNode>;
// private methods
// lifecycle
_mount: () => Component;
_update: (vnode: VNode) => void;
_updateFromParent: (
propsData?: Object,
listeners?: { [key: string]: Function | Array<Function> },
parentVnode: VNode,
renderChildren: Array<VNode> | () => Array<VNode>
) => void;
// rendering
_render: () => VNode;
__patch__: (a: Element | VNode | void, b: VNode) => Element;
__h__: (
tag?: string | Component | Object,
data?: Object,
children?: Array<?VNode> | string,
namespace?: string
) => VNode;
__toString__: (value: any) => string;
__resolveFilter__: (id: string) => Function;
__renderList__: (
val: any,
render: Function
) => ?Array<VNode>;
__registerRef__: (
key: string,
ref: Component | Element,
vFor: boolean,
isRemoval: boolean
) => void;
// allow dynamic method registration
[key: string]: any
}
declare interface GlobalAPI {
cid: number;
options: Object;
config: Config;
util: Object;
extend: (options: Object) => Function;
set: (obj: Object, key: string, value: any) => void;
delete: (obj: Object, key: string) => void;
nextTick: (fn: Function, context?: Object) => void;
use: (plugin: Function | Object) => void;
mixin: (mixin: Object) => void;
compile: (template: string) => { render: Function, staticRenderFns: Array<Function> };
directive: (id: string, def?: Function | Object) => Function | Object | void;
component: (id: string, def?: Class<Component> | Object) => Class<Component>;
transition: (id: string, def?: Object) => Object | void;
filter: (id: string, def?: Function) => Function | void;
// allow dynamic method registration
[key: string]: any
}

View File

@ -1,17 +1,17 @@
/*
* not type checking this file because flow doesn't like dynamically setting
* fields on a class
*/
/* @flow */
import config from '../config'
import { warn, isPlainObject } from '../util/index'
export function initAssetRegisters (Vue) {
export function initAssetRegisters (Vue: GlobalAPI) {
/**
* Create asset registration methods.
*/
config._assetTypes.forEach(type => {
Vue[type] = function (id, definition) {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {

View File

@ -1,10 +1,10 @@
/* @flow */
import type Vue from '../instance/index'
import config from '../config'
import { init } from '../instance/init'
import { warn, mergeOptions } from '../util/index'
export function initExtend (Vue: Class<Vue>) {
export function initExtend (Vue: GlobalAPI) {
/**
* Each instance constructor, including Vue, has a unique
* cid. This enables us to create wrapped "child
@ -16,7 +16,7 @@ export function initExtend (Vue: Class<Vue>) {
/**
* Class inheritance
*/
Vue.extend = function (extendOptions: Object): Class<any> {
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const isFirstExtend = Super.cid === 0
@ -34,7 +34,7 @@ export function initExtend (Vue: Class<Vue>) {
}
}
const Sub = function VueComponent (options) {
this._init(options)
init(this, options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from '../instance/index'
import config from '../config'
import * as util from '../util/index'
import { initUse } from './use'
@ -9,7 +8,7 @@ import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
export function initGlobalAPI (Vue: Class<Vue>) {
export function initGlobalAPI (Vue: GlobalAPI) {
Vue.config = config
Vue.util = util
Vue.set = set

View File

@ -1,9 +1,8 @@
/* @flow */
import type Vue from '../instance/index'
import { mergeOptions } from '../util/index'
export function initMixin (Vue: Class<Vue>) {
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
Vue.options = mergeOptions(Vue.options, mixin)
}

View File

@ -1,9 +1,8 @@
/* @flow */
import type Vue from '../instance/index'
import { toArray } from '../util/index'
export function initUse (Vue: Class<Vue>) {
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
/* istanbul ignore if */
if (plugin.installed) {

View File

@ -1,11 +1,9 @@
import Vue from './instance/index'
import config from './config'
import { initGlobalAPI } from './global-api/index'
import Vue from './instance/index'
initGlobalAPI(Vue)
// defining $isServer flag here because flow cannot handle
// Object.defineProperty getters
Object.defineProperty(Vue.prototype, '$isServer', {
get: () => config._isServer
})

View File

@ -1,10 +1,9 @@
/* @flow */
import type Vue from './index'
import { toArray } from '../util/index'
import { updateListeners } from '../vdom/helpers'
export function initEvents (vm: Vue) {
export function initEvents (vm: Component) {
vm._events = Object.create(null)
// init parent attached events
const listeners = vm.$options._parentListeners
@ -15,37 +14,39 @@ export function initEvents (vm: Vue) {
}
}
export function eventsMixin (Vue: Class<Vue>) {
Vue.prototype.$on = function (event: string, fn: Function): Vue {
(this._events[event] || (this._events[event] = [])).push(fn)
return this
export function eventsMixin (Vue: Class<Component>) {
Vue.prototype.$on = function (event: string, fn: Function): Component {
const vm: Component = this
;(vm._events[event] || (vm._events[event] = [])).push(fn)
return vm
}
Vue.prototype.$once = function (event: string, fn: Function): Vue {
const self = this
Vue.prototype.$once = function (event: string, fn: Function): Component {
const vm: Component = this
function on () {
self.$off(event, on)
fn.apply(this, arguments)
vm.$off(event, on)
fn.apply(vm, arguments)
}
on.fn = fn
this.$on(event, on)
return this
vm.$on(event, on)
return vm
}
Vue.prototype.$off = function (event?: string, fn?: Function): Vue {
Vue.prototype.$off = function (event?: string, fn?: Function): Component {
const vm: Component = this
// all
if (!arguments.length) {
this._events = Object.create(null)
return this
vm._events = Object.create(null)
return vm
}
// specific event
const cbs = this._events[event]
const cbs = vm._events[event]
if (!cbs) {
return this
return vm
}
if (arguments.length === 1) {
this._events[event] = null
return this
vm._events[event] = null
return vm
}
// specific handler
let cb
@ -57,18 +58,19 @@ export function eventsMixin (Vue: Class<Vue>) {
break
}
}
return this
return vm
}
Vue.prototype.$emit = function (event: string): Vue {
let cbs = this._events[event]
Vue.prototype.$emit = function (event: string): Component {
const vm: Component = this
let cbs = vm._events[event]
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
for (let i = 0, l = cbs.length; i < l; i++) {
cbs[i].apply(this, args)
cbs[i].apply(vm, args)
}
}
return this
return vm
}
}

View File

@ -1,137 +1,16 @@
/* @flow */
import { init } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import type { Config } from '../config'
import type VNode from '../vdom/vnode'
import type Watcher from '../observer/watcher'
import { initProxy } from './proxy'
import { initState, stateMixin } from './state'
import { initRender, renderMixin } from './render'
import { initEvents, eventsMixin } from './events'
import { initLifecycle, lifecycleMixin, callHook } from './lifecycle'
import { mergeOptions } from '../util/index'
let uid = 0
export default class Vue {
// static properties
static cid: number;
static options: Object;
static config: Config;
static util: Object;
// static methods
static set: (obj: Object, key: string, value: any) => void;
static delete: (obj: Object, key: string) => void;
static nextTick: (fn: Function, context?: Object) => void;
static use: (plugin: Function | Object) => void;
static mixin: (mixin: Object) => void;
static extend: (options: Object) => Class<any>;
static compile: (template: string) => { render: Function, staticRenderFns: Array<Function> };
// assets
static directive: (id: string, def?: Function | Object) => Function | Object | void;
static component: (id: string, def?: Class<any> | Object) => Class<any>;
static transition: (id: string, def?: Object) => Object | void;
static filter: (id: string, def?: Function) => Function | void;
// public properties
$el: Element | void;
$data: Object;
$options: Object;
$parent: Vue | void;
$root: Vue;
$children: Array<Vue>;
$refs: { [key: string]: Vue | Element };
$slots: { [key: string]: Array<VNode> };
$isServer: boolean;
// public methods
$mount: (el?: Element | string) => Vue;
$forceUpdate: () => void;
$destroy: () => void;
$watch: (expOrFn: string | Function, cb: Function, options?: Object) => Function;
$on: (event: string, fn: Function) => Vue;
$once: (event: string, fn: Function) => Vue;
$off: (event?: string, fn?: Function) => Vue;
$emit: (event: string, ...args: Array<any>) => Vue;
$nextTick: (fn: Function) => void;
$createElement: (
tag?: string | Vue,
data?: Object,
children?: Array<?VNode> | string,
namespace?: string
) => VNode;
// private properties
_uid: number;
_isVue: true;
_renderProxy: Vue;
_watchers: Array<Watcher>;
_data: Object;
_events: { [key: string]: Array<Function> };
_isMounted: boolean;
_isDestroyed: boolean;
_isBeingDestroyed: boolean;
_vnode: ?VNode;
_staticTrees: ?Array<VNode>;
// private methods
// lifecycle
_mount: () => Vue;
_update: (vnode: VNode) => void;
_updateFromParent: (propsData?: Object, listeners?: Object, parentVnode: VNode, renderChildren: Array<VNode> | () => Array<VNode>) => void;
// rendering
_render: () => VNode;
__h__: (
tag?: string | Vue,
data?: Object,
children?: Array<?VNode> | string,
namespace?: string
) => VNode;
__toString__: (value: any) => string;
__resolveFilter__: (id: string) => Function;
__renderList__: (
val: any,
render: Function
) => ?Array<VNode>;
__registerRef__: (
key: string,
ref: Vue | Element,
vFor: boolean,
isRemoval: boolean
) => void;
constructor (options?: Object) {
this._init(options)
}
_init (options?: Object) {
// a uid
this._uid = uid++
// a flag to avoid this being observed
this._isVue = true
// merge options
this.$options = mergeOptions(
this.constructor.options,
options || {},
this
)
if (process.env.NODE_ENV !== 'production') {
initProxy(this)
} else {
this._renderProxy = this
}
initLifecycle(this)
initEvents(this)
callHook(this, 'init')
initState(this)
callHook(this, 'created')
initRender(this)
}
function Vue (options) {
init(this, options)
}
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue

34
src/core/instance/init.js Normal file
View File

@ -0,0 +1,34 @@
/* @flow */
import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { initLifecycle, callHook } from './lifecycle'
import { mergeOptions } from '../util/index'
let uid = 0
export function init (vm: Component, options?: Object) {
// a uid
vm._uid = uid++
// a flag to avoid this being observed
vm._isVue = true
// merge options
vm.$options = mergeOptions(
vm.constructor.options,
options || {},
vm
)
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
vm._renderProxy = vm
}
initLifecycle(vm)
initEvents(vm)
callHook(vm, 'init')
initState(vm)
callHook(vm, 'created')
initRender(vm)
}

View File

@ -1,13 +1,12 @@
/* @flow */
import type Vue from './index'
import type VNode from '../vdom/vnode'
import Watcher from '../observer/watcher'
import { warn, validateProp, remove } from '../util/index'
import { observerState } from '../observer/index'
import { updateListeners } from '../vdom/helpers'
export function initLifecycle (vm: Vue) {
export function initLifecycle (vm: Component) {
const options = vm.$options
vm.$parent = options.parent
@ -24,56 +23,58 @@ export function initLifecycle (vm: Vue) {
vm._isBeingDestroyed = false
}
export function lifecycleMixin (Vue: Class<Vue>) {
Vue.prototype._mount = function (): Vue {
if (!this.$options.render) {
this.$options.render = () => this.$createElement('div')
export function lifecycleMixin (Vue: Class<Component>) {
Vue.prototype._mount = function (): Component {
const vm: Component = this
if (!vm.$options.render) {
vm.$options.render = () => vm.$createElement('div')
if (process.env.NODE_ENV !== 'production') {
if (this.$options.template) {
if (vm.$options.template) {
warn(
'You are using the runtime-only build of Vue where the template ' +
'option is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.',
this
vm
)
} else {
warn(
'Failed to mount component: template or render function not defined.',
this
vm
)
}
}
}
callHook(this, 'beforeMount')
this._watcher = new Watcher(this, this._render, this._update)
this._update(this._watcher.value)
this._isMounted = true
callHook(vm, 'beforeMount')
vm._watcher = new Watcher(vm, vm._render, vm._update)
vm._update(vm._watcher.value)
vm._isMounted = true
// root instance, call mounted on self
if (this.$root === this) {
callHook(this, 'mounted')
if (vm.$root === vm) {
callHook(vm, 'mounted')
}
return this
return vm
}
Vue.prototype._update = function (vnode: VNode) {
if (this._isMounted) {
callHook(this, 'beforeUpdate')
const vm: Component = this
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
if (!this._vnode) {
if (!vm._vnode) {
// Vue.prototype.__patch__ is injected in entry points
// based on the rendering backend used.
this.$el = this.__patch__(this.$el, vnode)
vm.$el = vm.__patch__(vm.$el, vnode)
} else {
this.$el = this.__patch__(this._vnode, vnode)
vm.$el = vm.__patch__(vm._vnode, vnode)
}
this._vnode = vnode
vm._vnode = vnode
// update parent vnode element after patch
const parentNode = this.$options._parentVnode
const parentNode = vm.$options._parentVnode
if (parentNode) {
parentNode.elm = this.$el
parentNode.elm = vm.$el
}
if (this._isMounted) {
callHook(this, 'updated')
if (vm._isMounted) {
callHook(vm, 'updated')
}
}
@ -83,66 +84,65 @@ export function lifecycleMixin (Vue: Class<Vue>) {
parentVnode: VNode,
renderChildren: Array<VNode> | () => Array<VNode>
) {
this.$options._parentVnode = parentVnode
this.$options._renderChildren = renderChildren
const vm: Component = this
vm.$options._parentVnode = parentVnode
vm.$options._renderChildren = renderChildren
// update props
if (propsData && this.$options.props) {
if (propsData && vm.$options.props) {
observerState.shouldConvert = false
const propKeys = this.$options.propKeys
const propKeys = vm.$options.propKeys
for (let i = 0; i < propKeys.length; i++) {
const key = propKeys[i]
this[key] = validateProp(this, key, propsData)
vm[key] = validateProp(vm, key, propsData)
}
observerState.shouldConvert = true
}
// update listeners
if (listeners) {
const oldListeners = this.$options._parentListeners
this.$options._parentListeners = listeners
const oldListeners = vm.$options._parentListeners
vm.$options._parentListeners = listeners
updateListeners(listeners, oldListeners || {}, (event, handler) => {
this.$on(event, handler)
vm.$on(event, handler)
})
}
}
Vue.prototype.$forceUpdate = function () {
this._watcher.update()
const vm: Component = this
vm._watcher.update()
}
Vue.prototype.$destroy = function () {
if (this._isDestroyed) {
const vm: Component = this
if (vm._isDestroyed) {
return
}
callHook(this, 'beforeDestroy')
this._isBeingDestroyed = true
callHook(vm, 'beforeDestroy')
vm._isBeingDestroyed = true
// remove self from parent
const parent = this.$parent
const parent = vm.$parent
if (parent && !parent._isBeingDestroyed) {
remove(parent.$children, this)
}
// unregister ref
if (this._ref) {
this._context.$refs[this._ref] = undefined
remove(parent.$children, vm)
}
// teardown watchers
let i = this._watchers.length
let i = vm._watchers.length
while (i--) {
this._watchers[i].teardown()
vm._watchers[i].teardown()
}
// remove reference from data ob
// frozen object may not have observer.
if (this._data.__ob__) {
this._data.__ob__.removeVm(this)
if (vm._data.__ob__) {
vm._data.__ob__.removeVm(vm)
}
// call the last hook...
this._isDestroyed = true
callHook(this, 'destroyed')
vm._isDestroyed = true
callHook(vm, 'destroyed')
// turn off all instance listeners.
this.$off()
vm.$off()
}
}
export function callHook (vm: Vue, hook: string) {
export function callHook (vm: Component, hook: string) {
vm.$emit('pre-hook:' + hook)
const handlers = vm.$options[hook]
if (handlers) {

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from './index'
import type VNode from '../vdom/vnode'
import createElement from '../vdom/create-element'
import { emptyVNode } from '../vdom/vnode'
@ -8,11 +7,13 @@ import { flatten } from '../vdom/helpers'
import { bind, remove, isObject, renderString } from 'shared/util'
import { resolveAsset, nextTick } from '../util/index'
export const renderState = {
export const renderState: {
activeInstance: Component | null
} = {
activeInstance: null
}
export function initRender (vm: Vue) {
export function initRender (vm: Component) {
vm._vnode = null
vm._staticTrees = null
vm.$slots = {}
@ -24,26 +25,27 @@ export function initRender (vm: Vue) {
}
}
export function renderMixin (Vue: Class<Vue>) {
Vue.prototype.$nextTick = function (fn) {
export function renderMixin (Vue: Class<Component>) {
Vue.prototype.$nextTick = function (fn: Function) {
nextTick(fn, this)
}
Vue.prototype._render = function (): VNode {
if (!this._isMounted) {
const vm: Component = this
if (!vm._isMounted) {
// render static sub-trees for once on initial render
renderStaticTrees(this)
renderStaticTrees(vm)
}
const prev = renderState.activeInstance
renderState.activeInstance = this
const { render, _renderChildren, _parentVnode } = this.$options
renderState.activeInstance = vm
const { render, _renderChildren, _parentVnode } = vm.$options
// resolve slots. becaues slots are rendered in parent scope,
// we set the activeInstance to parent.
if (_renderChildren) {
resolveSlots(this, _renderChildren)
resolveSlots(vm, _renderChildren)
}
// render self
const vnode = render.call(this._renderProxy) || emptyVNode
const vnode = render.call(vm._renderProxy) || emptyVNode
// set parent
vnode.parent = _parentVnode
// restore render state
@ -97,16 +99,17 @@ export function renderMixin (Vue: Class<Vue>) {
vFor: boolean,
isRemoval: boolean
) {
const refs = this.$refs
const vm: Component = this
const refs = vm.$refs
if (isRemoval) {
if (vFor) {
if (Array.isArray(refs[key])) {
remove(refs[key], ref)
} else {
refs[key] = undefined
}
} else {
if (vFor) {
if (refs[key]) {
if (Array.isArray(refs[key])) {
refs[key].push(ref)
} else {
refs[key] = [ref]
@ -118,7 +121,7 @@ export function renderMixin (Vue: Class<Vue>) {
}
}
function renderStaticTrees (vm: Vue) {
function renderStaticTrees (vm: Component) {
const staticRenderFns = vm.$options.staticRenderFns
if (staticRenderFns) {
const trees = vm._staticTrees = new Array(staticRenderFns.length)
@ -128,7 +131,7 @@ function renderStaticTrees (vm: Vue) {
}
}
function resolveSlots (vm: Vue, renderChildren: () => Array<?VNode> | void) {
function resolveSlots (vm: Component, renderChildren: () => Array<?VNode> | void) {
if (renderChildren) {
const children = flatten(renderChildren())
const slots = {}

View File

@ -1,4 +1,4 @@
/* Not type checking this file because flow doesn't play well with Object.defineProperty */
/* @flow */
import Watcher from '../observer/watcher'
import Dep from '../observer/dep'
@ -18,7 +18,7 @@ import {
noop
} from '../util/index'
export function initState (vm) {
export function initState (vm: Component) {
vm._watchers = []
initProps(vm)
initData(vm)
@ -27,7 +27,7 @@ export function initState (vm) {
initWatch(vm)
}
function initProps (vm) {
function initProps (vm: Component) {
const props = vm.$options.props
const propsData = vm.$options.propsData
if (props) {
@ -43,7 +43,7 @@ function initProps (vm) {
}
}
function initData (vm) {
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? data()
@ -65,35 +65,38 @@ function initData (vm) {
observe(data, vm)
}
function initComputed (vm) {
const computedSharedDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
}
function initComputed (vm: Component) {
const computed = vm.$options.computed
if (computed) {
for (const key in computed) {
const userDef = computed[key]
const def = {
enumerable: true,
configurable: true
}
if (typeof userDef === 'function') {
def.get = makeComputedGetter(userDef, vm)
def.set = noop
computedSharedDefinition.get = makeComputedGetter(userDef, vm)
computedSharedDefinition.set = noop
} else {
def.get = userDef.get
computedSharedDefinition.get = userDef.get
? userDef.cache !== false
? makeComputedGetter(userDef.get, vm)
: bind(userDef.get, vm)
: noop
def.set = userDef.set
computedSharedDefinition.set = userDef.set
? bind(userDef.set, vm)
: noop
}
Object.defineProperty(vm, key, def)
Object.defineProperty(vm, key, computedSharedDefinition)
}
}
}
function makeComputedGetter (getter, owner) {
const watcher = new Watcher(owner, getter, null, {
function makeComputedGetter (getter: Function, owner: Component): Function {
const watcher = new Watcher(owner, getter, noop, {
lazy: true
})
return function computedGetter () {
@ -107,7 +110,7 @@ function makeComputedGetter (getter, owner) {
}
}
function initMethods (vm) {
function initMethods (vm: Component) {
const methods = vm.$options.methods
if (methods) {
for (const key in methods) {
@ -116,7 +119,7 @@ function initMethods (vm) {
}
}
function initWatch (vm) {
function initWatch (vm: Component) {
const watch = vm.$options.watch
if (watch) {
for (const key in watch) {
@ -132,7 +135,7 @@ function initWatch (vm) {
}
}
function createWatcher (vm, key, handler) {
function createWatcher (vm: Component, key: string, handler: any) {
let options
if (isPlainObject(handler)) {
options = handler
@ -144,24 +147,32 @@ function createWatcher (vm, key, handler) {
vm.$watch(key, handler, options)
}
export function stateMixin (Vue) {
Object.defineProperty(Vue.prototype, '$data', {
get () {
return this._data
},
set (newData) {
if (newData !== this._data) {
setData(this, newData)
}
export function stateMixin (Vue: Class<Component>) {
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
const dataDef = {}
dataDef.get = function () {
return this._data
}
dataDef.set = function (newData: Object) {
if (newData !== this._data) {
setData(this, newData)
}
})
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Vue.prototype.$watch = function (expOrFn, cb, options) {
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: Function,
options?: Object
): Function {
const vm: Component = this
options = options || {}
options.user = true
const watcher = new Watcher(this, expOrFn, cb, options)
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
cb.call(this, watcher.value)
cb.call(vm, watcher.value)
}
return function unwatchFn () {
watcher.teardown()
@ -169,7 +180,7 @@ export function stateMixin (Vue) {
}
}
function setData (vm, newData) {
function setData (vm: Component, newData: Object) {
newData = newData || {}
const oldData = vm._data
vm._data = newData

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from '../instance/index'
import config from '../config'
import Dep from './dep'
import { arrayMethods } from './array'
@ -36,7 +35,7 @@ export const observerState = {
export class Observer {
value: any;
dep: Dep;
vms: ?Array<Vue>;
vms: ?Array<Component>;
constructor (value: any) {
this.value = value
@ -81,7 +80,7 @@ export class Observer {
* digest the watchers. This is only called when the object
* is observed as an instance's root $data.
*/
addVm (vm: Vue) {
addVm (vm: Component) {
(this.vms || (this.vms = [])).push(vm)
}
@ -89,7 +88,7 @@ export class Observer {
* Remove an owner vm. This is called when the object is
* swapped out as an instance's $data object.
*/
removeVm (vm: Vue) {
removeVm (vm: Component) {
remove(this.vms, vm)
}
}
@ -109,11 +108,8 @@ function protoAugment (target, src: Object) {
/**
* Augment an target Object or Array by defining
* hidden properties.
*
* @param {Object|Array} target
* @param {Object} proto
*/
function copyAugment (target, src, keys) {
function copyAugment (target: Object, src: Object, keys: Array<string>) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
def(target, key, src[key])
@ -125,7 +121,7 @@ function copyAugment (target, src, keys) {
* returns the new observer if successfully observed,
* or the existing observer if the value already has one.
*/
export function observe (value: any, vm?: Vue): Observer | void {
export function observe (value: any, vm?: Component): Observer | void {
if (!isObject(value)) {
return
}
@ -266,7 +262,7 @@ export function del (obj: Object, key: string) {
}
}
export function proxy (vm: Vue, key: string) {
export function proxy (vm: Component, key: string) {
if (!isReserved(key)) {
Object.defineProperty(vm, key, {
configurable: true,
@ -282,7 +278,7 @@ export function proxy (vm: Vue, key: string) {
}
// using Object type to avoid flow complaining
export function unproxy (vm: Object, key: string) {
export function unproxy (vm: Component, key: string) {
if (!isReserved(key)) {
delete vm[key]
}

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from '../instance/index'
import Dep from './dep'
import { queueWatcher } from './scheduler'
import {
@ -20,7 +19,7 @@ let prevTarget
* This is used for both the $watch() api and directives.
*/
export default class Watcher {
vm: Vue;
vm: Component;
expression: string;
cb: Function;
id: number;
@ -37,7 +36,7 @@ export default class Watcher {
value: any;
constructor (
vm: Vue,
vm: Component,
expOrFn: string | Function,
cb: Function,
options?: Object = {}

View File

@ -69,7 +69,7 @@ function mergeData (to: Object, from: ?Object): Object {
strats.data = function (
parentVal: any,
childVal: any,
vm?: Vue
vm?: Component
): ?Function {
if (!vm) {
// in a Vue.extend merge, both should be functions
@ -276,7 +276,7 @@ function guardDirectives (options: Object) {
* Merge two option objects into a new one.
* Core utility used in both instantiation and inheritance.
*/
export function mergeOptions (parent: Object, child: Object, vm?: Vue) {
export function mergeOptions (parent: Object, child: Object, vm?: Component) {
guardComponents(child)
guardProps(child)
guardDirectives(child)

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from '../instance/index'
import { hasOwn, isObject, isPlainObject } from 'shared/util'
import { observe, observerState } from '../observer/index'
import { warn } from './debug'
@ -12,7 +11,7 @@ type PropOptions = {
validator: ?Function
}
export function validateProp (vm: Vue, key: string, propsData: ?Object): any {
export function validateProp (vm: Component, key: string, propsData: ?Object): any {
if (!propsData) return
const prop = vm.$options.props[key]
const absent = hasOwn(propsData, key)
@ -35,7 +34,7 @@ export function validateProp (vm: Vue, key: string, propsData: ?Object): any {
/**
* Get the default value of a prop.
*/
function getPropDefaultValue (vm: Vue, prop: PropOptions, name: string): any {
function getPropDefaultValue (vm: Component, prop: PropOptions, name: string): any {
// no default, return undefined
if (!hasOwn(prop, 'default')) {
// absent boolean value defaults to false
@ -66,7 +65,7 @@ function assertProp (
prop: PropOptions,
name: string,
value: any,
vm: Vue,
vm: Component,
absent: boolean
) {
if (prop.required && absent) {

View File

@ -1,9 +1,9 @@
/* @flow */
import Vue from './web-runtime'
import config from 'core/config'
import { warn, cached } from 'core/util/index'
import { query } from 'web/util/index'
import Vue from './web-runtime'
import { compileToFunctions } from './web-compiler'
const idToTemplate = cached(id => query(id).innerHTML)

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from 'core/instance/index'
import RenderStream from './render-stream'
import { createRenderFunction } from './render'
import { warn } from 'core/util/debug'
@ -30,7 +29,7 @@ export function createRenderer ({
return {
renderToString (
component: Vue,
component: Component,
done: (err: ?Error, res: ?string) => any
): void {
let result = ''
@ -58,7 +57,7 @@ export function createRenderer ({
}
},
renderToStream (component: Vue): RenderStream {
renderToStream (component: Component): RenderStream {
return new RenderStream((write, done) => {
render(component, write, done)
})

View File

@ -1,6 +1,5 @@
/* @flow */
import type Vue from 'core/instance/index'
import type VNode from 'core/vdom/vnode'
import { createComponentInstanceForVnode } from 'core/vdom/create-component'
@ -82,7 +81,7 @@ export function createRenderFunction (
return markup + '>'
}
return function render (component: Vue, write: Function, done: Function) {
return function render (component: Component, write: Function, done: Function) {
renderNode(component._render(), write, done, true)
}
}