diff --git a/src/core/instance/state.js b/src/core/instance/state.js index d2d8fa14998..81306663f77 100644 --- a/src/core/instance/state.js +++ b/src/core/instance/state.js @@ -60,6 +60,16 @@ const isReservedProp = { slot: 1 } +function checkOptionType (vm: Component, name: string) { + const option = vm.$options[name] + if (!isPlainObject(option)) { + warn( + `component option "${name}" should be an object.`, + vm + ) + } +} + function initProps (vm: Component, propsOptions: Object) { const propsData = vm.$options.propsData || {} const props = vm._props = {} @@ -148,6 +158,7 @@ function getData (data: Function, vm: Component): any { const computedWatcherOptions = { lazy: true } function initComputed (vm: Component, computed: Object) { + process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'computed') const watchers = vm._computedWatchers = Object.create(null) for (const key in computed) { @@ -213,6 +224,7 @@ function createComputedGetter (key) { } function initMethods (vm: Component, methods: Object) { + process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'methods') const props = vm.$options.props for (const key in methods) { vm[key] = methods[key] == null ? noop : bind(methods[key], vm) @@ -235,6 +247,7 @@ function initMethods (vm: Component, methods: Object) { } function initWatch (vm: Component, watch: Object) { + process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'watch') for (const key in watch) { const handler = watch[key] if (Array.isArray(handler)) { diff --git a/test/helpers/test-object-option.js b/test/helpers/test-object-option.js new file mode 100644 index 00000000000..1012ea10b44 --- /dev/null +++ b/test/helpers/test-object-option.js @@ -0,0 +1,17 @@ +import Vue from 'vue' + +export default function testObjectOption (name: string) { + it('should warn non object', () => { + const options = {} + options[name] = () => {} + new Vue(options) + expect(`component option "${name}" should be an object`).toHaveBeenWarned() + }) + + it('don\'t warn when is an object', () => { + const options = {} + options[name] = {} + new Vue(options) + expect(`component option "${name}" should be an object`).not.toHaveBeenWarned() + }) +} diff --git a/test/unit/features/options/computed.spec.js b/test/unit/features/options/computed.spec.js index d4515b011ba..a48c7ed13b7 100644 --- a/test/unit/features/options/computed.spec.js +++ b/test/unit/features/options/computed.spec.js @@ -1,4 +1,5 @@ import Vue from 'vue' +import testObjectOption from '../../../helpers/test-object-option' describe('Options computed', () => { it('basic usage', done => { @@ -48,6 +49,8 @@ describe('Options computed', () => { }).then(done) }) + testObjectOption('computed') + it('warn with setter and no getter', () => { const vm = new Vue({ template: ` diff --git a/test/unit/features/options/methods.spec.js b/test/unit/features/options/methods.spec.js index 3e6991144be..66039c968d7 100644 --- a/test/unit/features/options/methods.spec.js +++ b/test/unit/features/options/methods.spec.js @@ -1,4 +1,5 @@ import Vue from 'vue' +import testObjectOption from '../../../helpers/test-object-option' describe('Options methods', () => { it('should have correct context', () => { @@ -16,6 +17,8 @@ describe('Options methods', () => { expect(vm.a).toBe(2) }) + testObjectOption('methods') + it('should warn undefined methods', () => { new Vue({ methods: { diff --git a/test/unit/features/options/watch.spec.js b/test/unit/features/options/watch.spec.js index e0111d184c0..702cd2b8c4e 100644 --- a/test/unit/features/options/watch.spec.js +++ b/test/unit/features/options/watch.spec.js @@ -1,4 +1,5 @@ import Vue from 'vue' +import testObjectOption from '../../../helpers/test-object-option' describe('Options watch', () => { let spy @@ -23,6 +24,8 @@ describe('Options watch', () => { }).then(done) }) + testObjectOption('watch') + it('string method name', done => { const vm = new Vue({ data: {