From da91541796698a6d049df8d4ffc2685ff8c0f78a Mon Sep 17 00:00:00 2001 From: daiwei Date: Wed, 19 Jul 2023 14:17:40 +0800 Subject: [PATCH 1/5] fix(reactivity): avoid wrapping extended array methods close #11570 --- packages/reactivity/src/arrayInstrumentations.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/reactivity/src/arrayInstrumentations.ts b/packages/reactivity/src/arrayInstrumentations.ts index 69f08d6c5d1..fa40f1687b3 100644 --- a/packages/reactivity/src/arrayInstrumentations.ts +++ b/packages/reactivity/src/arrayInstrumentations.ts @@ -227,6 +227,7 @@ function iterator( // higher than that type ArrayMethods = keyof Array | 'findLast' | 'findLastIndex' +const arrayProto = Array.prototype // instrument functions that read (potentially) all items // to take ARRAY_ITERATE dependency function apply( @@ -237,6 +238,12 @@ function apply( wrappedRetFn?: (result: any) => unknown, ) { const arr = shallowReadArray(self) + // @ts-expect-error + if (arr[method] !== arrayProto[method]) { + // @ts-expect-error + return arr[method](fn, thisArg) + } + let needsWrap = false let wrappedFn = fn if (arr !== self) { From 674082bdc8df709ea9d4a699591a1e10bc0f6ab4 Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 9 Aug 2024 10:06:32 +0800 Subject: [PATCH 2/5] test: add test case --- .../reactivity/__tests__/reactiveArray.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/reactivity/__tests__/reactiveArray.spec.ts b/packages/reactivity/__tests__/reactiveArray.spec.ts index 6ea3c953957..48732e663e0 100644 --- a/packages/reactivity/__tests__/reactiveArray.spec.ts +++ b/packages/reactivity/__tests__/reactiveArray.spec.ts @@ -2,6 +2,7 @@ import { type ComputedRef, computed } from '../src/computed' import { isReactive, reactive, shallowReactive, toRaw } from '../src/reactive' import { isRef, ref } from '../src/ref' import { effect } from '../src/effect' +import { expect } from 'vitest' describe('reactivity/reactive/Array', () => { test('should make Array reactive', () => { @@ -622,5 +623,22 @@ describe('reactivity/reactive/Array', () => { const firstItem = Array.from(deep.values())[0] expect(isReactive(firstItem)).toBe(true) }) + + test('extend methods', () => { + class Collection extends Array { + find(id: any) { + return super.find(obj => obj.id === id) + } + } + + const state = reactive({ + things: new Collection(), + }) + + const val = { id: 'foo', value: 'bar' } + state.things.push(val) + + expect(state.things.find('foo')).toBe(val) + }) }) }) From ed31aad993fe22c6a1112c58ba56929b3456717d Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 9 Aug 2024 10:07:25 +0800 Subject: [PATCH 3/5] chore: tweaks --- packages/reactivity/__tests__/reactiveArray.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/reactivity/__tests__/reactiveArray.spec.ts b/packages/reactivity/__tests__/reactiveArray.spec.ts index 48732e663e0..897a3b1ed9c 100644 --- a/packages/reactivity/__tests__/reactiveArray.spec.ts +++ b/packages/reactivity/__tests__/reactiveArray.spec.ts @@ -2,7 +2,6 @@ import { type ComputedRef, computed } from '../src/computed' import { isReactive, reactive, shallowReactive, toRaw } from '../src/reactive' import { isRef, ref } from '../src/ref' import { effect } from '../src/effect' -import { expect } from 'vitest' describe('reactivity/reactive/Array', () => { test('should make Array reactive', () => { From daec59344db131612964e4bd8ad3d29208bc5972 Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 9 Aug 2024 13:39:53 +0800 Subject: [PATCH 4/5] chore: fix args --- packages/reactivity/src/arrayInstrumentations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reactivity/src/arrayInstrumentations.ts b/packages/reactivity/src/arrayInstrumentations.ts index fa40f1687b3..6b040f1d337 100644 --- a/packages/reactivity/src/arrayInstrumentations.ts +++ b/packages/reactivity/src/arrayInstrumentations.ts @@ -241,7 +241,7 @@ function apply( // @ts-expect-error if (arr[method] !== arrayProto[method]) { // @ts-expect-error - return arr[method](fn, thisArg) + return arr[method](...arrayProto.slice.call(arguments, 2)) } let needsWrap = false From a593dde6750f768436d210b25d4305b6226e94c3 Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 9 Aug 2024 13:52:38 +0800 Subject: [PATCH 5/5] chore: fix args --- packages/reactivity/src/arrayInstrumentations.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/reactivity/src/arrayInstrumentations.ts b/packages/reactivity/src/arrayInstrumentations.ts index 6b040f1d337..51955a1bf81 100644 --- a/packages/reactivity/src/arrayInstrumentations.ts +++ b/packages/reactivity/src/arrayInstrumentations.ts @@ -238,10 +238,10 @@ function apply( wrappedRetFn?: (result: any) => unknown, ) { const arr = shallowReadArray(self) - // @ts-expect-error - if (arr[method] !== arrayProto[method]) { - // @ts-expect-error - return arr[method](...arrayProto.slice.call(arguments, 2)) + let methodFn + // @ts-expect-error our code is limited to es2016 but user code is not + if ((methodFn = arr[method]) !== arrayProto[method]) { + return methodFn.apply(arr, arrayProto.slice.call(arguments, 2)) } let needsWrap = false @@ -258,8 +258,7 @@ function apply( } } } - // @ts-expect-error our code is limited to es2016 but user code is not - const result = arr[method](wrappedFn, thisArg) + const result = methodFn.call(arr, wrappedFn, thisArg) return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result }