diff --git a/packages/reactivity/__tests__/reactive.spec.ts b/packages/reactivity/__tests__/reactive.spec.ts index b7f9cdf4eb3..ab798ff2c8b 100644 --- a/packages/reactivity/__tests__/reactive.spec.ts +++ b/packages/reactivity/__tests__/reactive.spec.ts @@ -44,6 +44,24 @@ describe('reactivity/reactive', () => { expect(isReactive(observed.array[0])).toBe(true) }) + test('process subtypes of collections properly', () => { + class CustomMap extends Map { + count = 0 + + set(key: any, value: any): this { + super.set(key, value) + this.count++ + return this + } + } + + const testMap = new CustomMap() + const observed = reactive(testMap) + expect(observed.count).toBe(0) + observed.set('test', 'value') + expect(observed.count).toBe(1) + }) + test('observed value should proxy mutations to original (Object)', () => { const original: any = { foo: 1 } const observed = reactive(original) diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 4dea9e00c86..e7db1e0a071 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -18,7 +18,9 @@ export const enum ReactiveFlags { IS_READONLY = '__v_isReadonly', RAW = '__v_raw', REACTIVE = '__v_reactive', - READONLY = '__v_readonly' + READONLY = '__v_readonly', + + IS_COLLECTION = '__v_isCollection' } interface Target { @@ -28,9 +30,15 @@ interface Target { [ReactiveFlags.RAW]?: any [ReactiveFlags.REACTIVE]?: any [ReactiveFlags.READONLY]?: any + + [ReactiveFlags.IS_COLLECTION]?: boolean } -const collectionTypes = new Set([Set, Map, WeakMap, WeakSet]) +;([Set, Map, WeakMap, WeakSet] as Array).forEach( + collectionType => + (collectionType.prototype[ReactiveFlags.IS_COLLECTION] = true) +) + const isObservableType = /*#__PURE__*/ makeMap( 'Object,Array,Map,Set,WeakMap,WeakSet' ) @@ -151,9 +159,10 @@ function createReactiveObject( if (!canObserve(target)) { return target } + const observed = new Proxy( target, - collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers + target[ReactiveFlags.IS_COLLECTION] ? collectionHandlers : baseHandlers ) def(target, reactiveFlag, observed) return observed