Evan You 4 лет назад
Родитель
Сommit
cfc2c59132

+ 2 - 2
src/core/global-api/assets.ts

@@ -1,6 +1,6 @@
 import { ASSET_TYPES } from 'shared/constants'
 import type { GlobalAPI } from 'typescript/global-api'
-import { isPlainObject, validateComponentName } from '../util/index'
+import { isFunction, isPlainObject, validateComponentName } from '../util/index'
 
 export function initAssetRegisters(Vue: GlobalAPI) {
   /**
@@ -24,7 +24,7 @@ export function initAssetRegisters(Vue: GlobalAPI) {
           definition.name = definition.name || id
           definition = this.options._base.extend(definition)
         }
-        if (type === 'directive' && typeof definition === 'function') {
+        if (type === 'directive' && isFunction(definition)) {
           definition = { bind: definition, update: definition }
         }
         this.options[type + 's'][id] = definition

+ 3 - 3
src/core/global-api/use.ts

@@ -1,5 +1,5 @@
 import type { GlobalAPI } from 'typescript/global-api'
-import { toArray } from '../util/index'
+import { toArray, isFunction } from '../util/index'
 
 export function initUse(Vue: GlobalAPI) {
   Vue.use = function (plugin: Function | any) {
@@ -12,9 +12,9 @@ export function initUse(Vue: GlobalAPI) {
     // additional parameters
     const args = toArray(arguments, 1)
     args.unshift(this)
-    if (typeof plugin.install === 'function') {
+    if (isFunction(plugin.install)) {
       plugin.install.apply(plugin, args)
-    } else if (typeof plugin === 'function') {
+    } else if (isFunction(plugin)) {
       plugin.apply(null, args)
     }
     installedPlugins.push(plugin)

+ 5 - 10
src/core/instance/inject.ts

@@ -1,16 +1,12 @@
 import { hasOwn } from 'shared/util'
-import { warn, hasSymbol } from '../util/index'
+import { warn, hasSymbol, isFunction } from '../util/index'
 import { defineReactive, toggleObserving } from '../observer/index'
 import type { Component } from 'typescript/component'
 
 export function initProvide(vm: Component) {
   const provide = vm.$options.provide
   if (provide) {
-    vm._provided =
-      typeof provide === 'function'
-        ? // @ts-expect-error typing not correct
-          provide.call(vm)
-        : provide
+    vm._provided = isFunction(provide) ? provide.call(vm) : provide
   }
 }
 
@@ -63,10 +59,9 @@ export function resolveInject(
       if (!source) {
         if ('default' in inject[key]) {
           const provideDefault = inject[key].default
-          result[key] =
-            typeof provideDefault === 'function'
-              ? provideDefault.call(vm)
-              : provideDefault
+          result[key] = isFunction(provideDefault)
+            ? provideDefault.call(vm)
+            : provideDefault
         } else if (__DEV__) {
           warn(`Injection "${key as string}" not found`, vm)
         }

+ 3 - 3
src/core/instance/render-helpers/render-slot.ts

@@ -1,4 +1,4 @@
-import { extend, warn, isObject } from 'core/util/index'
+import { extend, warn, isObject, isFunction } from 'core/util/index'
 import VNode from 'core/vdom/vnode'
 
 /**
@@ -23,11 +23,11 @@ export function renderSlot(
     }
     nodes =
       scopedSlotFn(props) ||
-      (typeof fallbackRender === 'function' ? fallbackRender() : fallbackRender)
+      (isFunction(fallbackRender) ? fallbackRender() : fallbackRender)
   } else {
     nodes =
       this.$slots[name] ||
-      (typeof fallbackRender === 'function' ? fallbackRender() : fallbackRender)
+      (isFunction(fallbackRender) ? fallbackRender() : fallbackRender)
   }
 
   const target = props && props.slot

+ 7 - 6
src/core/instance/state.ts

@@ -26,7 +26,8 @@ import {
   isPlainObject,
   isServerRendering,
   isReservedAttribute,
-  invokeWithErrorHandling
+  invokeWithErrorHandling,
+  isFunction
 } from '../util/index'
 import type { Component } from '../../../typescript/component'
 
@@ -119,7 +120,7 @@ function initProps(vm: Component, propsOptions: Object) {
 
 function initData(vm: Component) {
   let data: any = vm.$options.data
-  data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
+  data = vm._data = isFunction(data) ? getData(data, vm) : data || {}
   if (!isPlainObject(data)) {
     data = {}
     __DEV__ &&
@@ -179,7 +180,7 @@ function initComputed(vm: Component, computed: Object) {
 
   for (const key in computed) {
     const userDef = computed[key]
-    const getter = typeof userDef === 'function' ? userDef : userDef.get
+    const getter = isFunction(userDef) ? userDef : userDef.get
     if (__DEV__ && getter == null) {
       warn(`Getter is missing for computed property "${key}".`, vm)
     }
@@ -217,10 +218,10 @@ function initComputed(vm: Component, computed: Object) {
 export function defineComputed(
   target: any,
   key: string,
-  userDef: Record<string, any> | Function
+  userDef: Record<string, any> | (() => any)
 ) {
   const shouldCache = !isServerRendering()
-  if (typeof userDef === 'function') {
+  if (isFunction(userDef)) {
     sharedPropertyDefinition.get = shouldCache
       ? createComputedGetter(key)
       : createGetterInvoker(userDef)
@@ -352,7 +353,7 @@ export function stateMixin(Vue: Component) {
   Vue.prototype.$delete = del
 
   Vue.prototype.$watch = function (
-    expOrFn: string | Function,
+    expOrFn: string | (() => any),
     cb: any,
     options?: Record<string, any>
   ): Function {

+ 4 - 3
src/core/observer/watcher.ts

@@ -7,7 +7,8 @@ import {
   handleError,
   invokeWithErrorHandling,
   noop,
-  bind
+  bind,
+  isFunction
 } from '../util/index'
 
 import { traverse } from './traverse'
@@ -46,7 +47,7 @@ export default class Watcher implements DepTarget {
 
   constructor(
     vm: Component | null,
-    expOrFn: string | Function,
+    expOrFn: string | (() => any),
     cb: Function,
     options?: {
       deep?: boolean
@@ -88,7 +89,7 @@ export default class Watcher implements DepTarget {
     this.newDepIds = new Set()
     this.expression = __DEV__ ? expOrFn.toString() : ''
     // parse expression for getter
-    if (typeof expOrFn === 'function') {
+    if (isFunction(expOrFn)) {
       this.getter = expOrFn
     } else {
       this.getter = parsePath(expOrFn)

+ 2 - 2
src/core/util/debug.ts

@@ -1,5 +1,5 @@
 import config from '../config'
-import { noop, isArray } from 'shared/util'
+import { noop, isArray, isFunction } from 'shared/util'
 import type { Component } from 'typescript/component'
 import { currentInstance } from 'v3/currentInstance'
 
@@ -36,7 +36,7 @@ if (__DEV__) {
       return '<Root>'
     }
     const options =
-      typeof vm === 'function' && (vm as any).cid != null
+      isFunction(vm) && (vm as any).cid != null
         ? (vm as any).options
         : vm._isVue
         ? vm.$options || (vm.constructor as any).options

+ 11 - 9
src/core/util/options.ts

@@ -3,7 +3,7 @@ import { warn } from './debug'
 import { set } from '../observer/index'
 import { unicodeRegExp } from './lang'
 import { nativeWatch, hasSymbol } from './env'
-import { isArray } from 'shared/util'
+import { isArray, isFunction } from 'shared/util'
 
 import { ASSET_TYPES, LIFECYCLE_HOOKS } from 'shared/constants'
 
@@ -102,17 +102,19 @@ export function mergeDataOrFn(
     // it has to be a function to pass previous merges.
     return function mergedDataFn() {
       return mergeData(
-        typeof childVal === 'function' ? childVal.call(this, this) : childVal,
-        typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal
+        isFunction(childVal) ? childVal.call(this, this) : childVal,
+        isFunction(parentVal) ? parentVal.call(this, this) : parentVal
       )
     }
   } else {
     return function mergedInstanceDataFn() {
       // instance merge
-      const instanceData =
-        typeof childVal === 'function' ? childVal.call(vm, vm) : childVal
-      const defaultData =
-        typeof parentVal === 'function' ? parentVal.call(vm, vm) : parentVal
+      const instanceData = isFunction(childVal)
+        ? childVal.call(vm, vm)
+        : childVal
+      const defaultData = isFunction(parentVal)
+        ? parentVal.call(vm, vm)
+        : parentVal
       if (instanceData) {
         return mergeData(instanceData, defaultData)
       } else {
@@ -369,7 +371,7 @@ function normalizeDirectives(options: Record<string, any>) {
   if (dirs) {
     for (const key in dirs) {
       const def = dirs[key]
-      if (typeof def === 'function') {
+      if (isFunction(def)) {
         dirs[key] = { bind: def, update: def }
       }
     }
@@ -399,7 +401,7 @@ export function mergeOptions(
     checkComponents(child)
   }
 
-  if (typeof child === 'function') {
+  if (isFunction(child)) {
     // @ts-expect-error
     child = child.options
   }

+ 2 - 1
src/core/util/props.ts

@@ -4,6 +4,7 @@ import {
   hasOwn,
   isArray,
   isObject,
+  isFunction,
   toRawType,
   hyphenate,
   capitalize,
@@ -93,7 +94,7 @@ function getPropDefaultValue(
   }
   // call factory function for non-Function types
   // a value is Function if its prototype is function even across different execution context
-  return typeof def === 'function' && getType(prop.type) !== 'Function'
+  return isFunction(def) && getType(prop.type) !== 'Function'
     ? def.call(vm)
     : def
 }

+ 9 - 6
src/platforms/web/runtime/modules/transition.ts

@@ -2,7 +2,14 @@ import { inBrowser, isIE9, warn } from 'core/util/index'
 import { mergeVNodeHook } from 'core/vdom/helpers/index'
 import { activeInstance } from 'core/instance/lifecycle'
 
-import { once, isDef, isUndef, isObject, toNumber } from 'shared/util'
+import {
+  once,
+  isDef,
+  isUndef,
+  isObject,
+  toNumber,
+  isFunction
+} from 'shared/util'
 
 import {
   nextFrame,
@@ -77,11 +84,7 @@ export function enter(vnode: VNodeWithData, toggleDisplay?: () => void) {
   const toClass = isAppear && appearToClass ? appearToClass : enterToClass
 
   const beforeEnterHook = isAppear ? beforeAppear || beforeEnter : beforeEnter
-  const enterHook = isAppear
-    ? typeof appear === 'function'
-      ? appear
-      : enter
-    : enter
+  const enterHook = isAppear ? (isFunction(appear) ? appear : enter) : enter
   const afterEnterHook = isAppear ? afterAppear || afterEnter : afterEnter
   const enterCancelledHook = isAppear
     ? appearCancelled || enterCancelled

+ 4 - 0
src/shared/util.ts

@@ -33,6 +33,10 @@ export function isPrimitive(value: any): boolean {
   )
 }
 
+export function isFunction(value: any): value is (...args: any[]) => any {
+  return typeof value === 'function'
+}
+
 /**
  * Quick object check - this is primarily used to tell
  * objects from primitive values when we know the value

+ 2 - 2
src/v3/apiSetup.ts

@@ -2,7 +2,7 @@ import { Component } from 'typescript/component'
 import type { SetupContext } from 'typescript/options'
 import { invokeWithErrorHandling, isReserved, warn } from '../core/util'
 import VNode from '../core/vdom/vnode'
-import { bind, isObject } from '../shared/util'
+import { bind, isFunction, isObject } from '../shared/util'
 import { currentInstance, setCurrentInstance } from './currentInstance'
 import { isRef } from './reactivity/ref'
 
@@ -30,7 +30,7 @@ export function initSetup(vm: Component) {
     )
     setCurrentInstance()
 
-    if (typeof setupResult === 'function') {
+    if (isFunction(setupResult)) {
       // render function
       // @ts-ignore
       options.render = setupResult

+ 3 - 2
src/v3/apiWatch.ts

@@ -5,6 +5,7 @@ import {
   warn,
   noop,
   isArray,
+  isFunction,
   emptyObject,
   remove,
   hasChanged,
@@ -210,13 +211,13 @@ function doWatch(
           return s.value
         } else if (isReactive(s)) {
           return traverse(s)
-        } else if (typeof s === 'function') {
+        } else if (isFunction(s)) {
           return call(s, WATCHER_GETTER)
         } else {
           __DEV__ && warnInvalidSource(s)
         }
       })
-  } else if (typeof source === 'function') {
+  } else if (isFunction(source)) {
     if (cb) {
       // getter with cb
       getter = () => call(source as Function, WATCHER_GETTER)

+ 2 - 2
src/v3/reactivity/computed.ts

@@ -1,4 +1,4 @@
-import { isServerRendering, noop, warn, def } from 'core/util'
+import { isServerRendering, noop, warn, def, isFunction } from 'core/util'
 import { Ref, RefFlag } from './ref'
 import Watcher from 'core/observer/watcher'
 import Dep from 'core/observer/dep'
@@ -41,7 +41,7 @@ export function computed<T>(
   let getter: ComputedGetter<T>
   let setter: ComputedSetter<T>
 
-  const onlyGetter = typeof getterOrOptions === 'function'
+  const onlyGetter = isFunction(getterOrOptions)
   if (onlyGetter) {
     getter = getterOrOptions
     setter = __DEV__

+ 1 - 1
test/unit/features/directives/class.spec.ts

@@ -9,7 +9,7 @@ function assertClass(assertions, done) {
   assertions.forEach(([value, expected], i) => {
     chain
       .then(() => {
-        if (typeof value === 'function') {
+        if (isFunction(value)) {
           value(vm.value)
         } else {
           vm.value = value

+ 1 - 1
test/unit/modules/compiler/codegen.spec.ts

@@ -16,7 +16,7 @@ function assertCodegen(template, generatedCode, ...args) {
       staticRenderFnCodes = arg
     } else if (isObject(arg)) {
       generateOptions = arg
-    } else if (typeof arg === 'function') {
+    } else if (isFunction(arg)) {
       proc = arg
     }
   }