diff --git a/README.md b/README.md
index 6528db2c..1f617ec5 100644
--- a/README.md
+++ b/README.md
@@ -445,6 +445,24 @@ defineComponent({
+### `computed().effect`
+
+
+
+⚠️ computed()
has a property effect
set to true
instead of a ReactiveEffect
.
+
+
+Due to the difference in implementation, there is no such concept as a `ReactiveEffect` in `@vue/composition-api`. Therefore, `effect` is merely `true` to enable differentiating computed from refs:
+
+```ts
+function isComputed(o: ComputedRef | unknown): o is ComputedRef
+function isComputed(o: any): o is ComputedRef {
+ return !!(isRef(o) && o.effect)
+}
+```
+
+
+
### Missing APIs
The following APIs introduced in Vue 3 are not available in this plugin.
diff --git a/src/apis/computed.ts b/src/apis/computed.ts
index 2cac40a8..fc85a5ee 100644
--- a/src/apis/computed.ts
+++ b/src/apis/computed.ts
@@ -1,5 +1,5 @@
import { getVueConstructor } from '../runtimeContext'
-import { createRef, Ref } from '../reactivity'
+import { createRef, ComputedRef, WritableComputedRef } from '../reactivity'
import {
warn,
noopFn,
@@ -9,12 +9,6 @@ import {
} from '../utils'
import { getCurrentScopeVM } from './effectScope'
-export interface ComputedRef extends WritableComputedRef {
- readonly value: T
-}
-
-export interface WritableComputedRef extends Ref {}
-
export type ComputedGetter = (ctx?: any) => T
export type ComputedSetter = (v: T) => void
@@ -102,6 +96,7 @@ export function computed(
get: computedGetter,
set: computedSetter,
},
- !setter
- )
+ !setter,
+ true
+ ) as WritableComputedRef | ComputedRef
}
diff --git a/src/apis/watch.ts b/src/apis/watch.ts
index 91f68c3f..633cdd1e 100644
--- a/src/apis/watch.ts
+++ b/src/apis/watch.ts
@@ -1,5 +1,5 @@
import { ComponentInstance } from '../component'
-import { Ref, isRef, isReactive } from '../reactivity'
+import { Ref, isRef, isReactive, ComputedRef } from '../reactivity'
import {
assert,
logError,
@@ -18,7 +18,6 @@ import {
WatcherPreFlushQueueKey,
WatcherPostFlushQueueKey,
} from '../utils/symbols'
-import { ComputedRef } from './computed'
import { getCurrentScopeVM } from './effectScope'
export type WatchEffect = (onInvalidate: InvalidateCbRegistrator) => void
diff --git a/src/reactivity/index.ts b/src/reactivity/index.ts
index 71f53de8..c9b2ea19 100644
--- a/src/reactivity/index.ts
+++ b/src/reactivity/index.ts
@@ -24,6 +24,8 @@ export { del } from './del'
export type {
Ref,
+ ComputedRef,
+ WritableComputedRef,
ToRefs,
UnwrapRef,
UnwrapRefSimple,
diff --git a/src/reactivity/ref.ts b/src/reactivity/ref.ts
index bf49d1c7..210d7f80 100644
--- a/src/reactivity/ref.ts
+++ b/src/reactivity/ref.ts
@@ -9,6 +9,19 @@ export interface Ref {
value: T
}
+export interface WritableComputedRef extends Ref {
+ /**
+ * `effect` is added to be able to differentiate refs from computed properties.
+ * **Differently from Vue 3, it's just `true`**. This is because there is no equivalent
+ * of `ReactiveEffect` in `@vue/composition-api`.
+ */
+ effect: true
+}
+
+export interface ComputedRef extends WritableComputedRef {
+ readonly value: T
+}
+
export type ToRefs = { [K in keyof T]: Ref }
export type CollectionTypes = IterableCollections | WeakCollections
@@ -58,14 +71,22 @@ export class RefImpl implements Ref {
}
}
-export function createRef(options: RefOption, readonly = false) {
+export function createRef(
+ options: RefOption,
+ isReadonly = false,
+ isComputed = false
+): RefImpl {
const r = new RefImpl(options)
+
+ // add effect to differentiate refs from computed
+ if (isComputed) (r as ComputedRef).effect = true
+
// seal the ref, this could prevent ref from being observed
// It's safe to seal the ref, since we really shouldn't extend it.
// related issues: #79
const sealed = Object.seal(r)
- if (readonly) readonlySet.set(sealed, true)
+ if (isReadonly) readonlySet.set(sealed, true)
return sealed
}
diff --git a/test/apis/computed.spec.js b/test/apis/computed.spec.js
index 78606e4f..af0ce83b 100644
--- a/test/apis/computed.spec.js
+++ b/test/apis/computed.spec.js
@@ -1,5 +1,5 @@
const Vue = require('vue/dist/vue.common.js')
-const { ref, computed, isReadonly } = require('../../src')
+const { ref, computed, isReadonly, reactive, isRef } = require('../../src')
describe('Hooks computed', () => {
beforeEach(() => {
@@ -212,4 +212,30 @@ describe('Hooks computed', () => {
expect(isReadonly(z.value)).toBe(false)
expect(isReadonly(z.value.a)).toBe(false)
})
+
+ it('passes isComputed', () => {
+ function isComputed(o) {
+ return !!(o && isRef(o) && o.effect)
+ }
+
+ expect(isComputed(computed(() => 2))).toBe(true)
+ expect(
+ isComputed(
+ computed({
+ get: () => 2,
+ set: () => {},
+ })
+ )
+ ).toBe(true)
+
+ expect(isComputed(ref({}))).toBe(false)
+ expect(isComputed(reactive({}))).toBe(false)
+ expect(isComputed({})).toBe(false)
+ expect(isComputed(undefined)).toBe(false)
+ expect(isComputed(null)).toBe(false)
+ expect(isComputed(true)).toBe(false)
+ expect(isComputed(20)).toBe(false)
+ expect(isComputed('hey')).toBe(false)
+ expect(isComputed('')).toBe(false)
+ })
})