expect('Invalid watch option: "foo"').toHaveBeenWarned()
})
+
+ test('computed with setter and no getter', () => {
+ const Comp = {
+ computed: {
+ foo: {
+ set() {}
+ }
+ },
+ render() {}
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(Comp), root)
+ expect('Computed property "foo" has no getter.').toHaveBeenWarned()
+ })
+
+ test('assigning to computed with no setter', () => {
+ let instance: any
+ const Comp = {
+ computed: {
+ foo: {
+ get() {}
+ }
+ },
+ mounted() {
+ instance = this
+ },
+ render() {}
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(Comp), root)
+ instance.foo = 1
+ expect(
+ 'Computed property "foo" was assigned to but it has no setter.'
+ ).toHaveBeenWarned()
+ })
})
})
isString,
isObject,
isArray,
- EMPTY_OBJ
+ EMPTY_OBJ,
+ NOOP
} from '@vue/shared'
import { computed } from './apiReactivity'
import { watch, WatchOptions, CleanupRegistrator } from './apiWatch'
if (computedOptions) {
for (const key in computedOptions) {
const opt = (computedOptions as ComputedOptions)[key]
- renderContext[key] = isFunction(opt)
- ? computed(opt.bind(ctx))
- : computed({
- get: opt.get.bind(ctx),
- set: opt.set.bind(ctx)
+
+ if (isFunction(opt)) {
+ renderContext[key] = computed(opt.bind(ctx))
+ } else {
+ const { get, set } = opt
+ if (isFunction(get)) {
+ renderContext[key] = computed({
+ get: get.bind(ctx),
+ set: isFunction(set)
+ ? set.bind(ctx)
+ : __DEV__
+ ? () => {
+ warn(
+ `Computed property "${key}" was assigned to but it has no setter.`
+ )
+ }
+ : NOOP
})
+ } else if (__DEV__) {
+ warn(`Computed property "${key}" has no getter.`)
+ }
+ }
}
}
if (methods) {