From 9817c80187bec6a3344c74d65fac92262de0fcdd Mon Sep 17 00:00:00 2001 From: Tycho Date: Tue, 3 Sep 2024 17:32:13 +0800 Subject: [PATCH] fix(reactivity): correctly handle method calls on user-extended arrays (#11760) close #11759 --- .../__tests__/reactiveArray.spec.ts | 21 +++++++++++++++++++ .../reactivity/src/arrayInstrumentations.ts | 10 ++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/reactivity/__tests__/reactiveArray.spec.ts b/packages/reactivity/__tests__/reactiveArray.spec.ts index fabafc21e25..3d97660e428 100644 --- a/packages/reactivity/__tests__/reactiveArray.spec.ts +++ b/packages/reactivity/__tests__/reactiveArray.spec.ts @@ -724,6 +724,27 @@ describe('reactivity/reactive/Array', () => { expect(state.things.forEach('foo', 'bar', 'baz')).toBeUndefined() expect(state.things.map('foo', 'bar', 'baz')).toEqual(['1', '2', '3']) expect(state.things.some('foo', 'bar', 'baz')).toBe(true) + + { + class Collection extends Array { + find(matcher: any) { + return super.find(matcher) + } + } + + const state = reactive({ + // @ts-expect-error + things: new Collection({ foo: '' }), + }) + + const bar = computed(() => { + return state.things.find((obj: any) => obj.foo === 'bar') + }) + bar.value + state.things[0].foo = 'bar' + + expect(bar.value).toEqual({ foo: 'bar' }) + } }) }) }) diff --git a/packages/reactivity/src/arrayInstrumentations.ts b/packages/reactivity/src/arrayInstrumentations.ts index 6cf7602eca5..6a15e2a184a 100644 --- a/packages/reactivity/src/arrayInstrumentations.ts +++ b/packages/reactivity/src/arrayInstrumentations.ts @@ -242,9 +242,13 @@ function apply( const needsWrap = arr !== self && !isShallow(self) // @ts-expect-error our code is limited to es2016 but user code is not const methodFn = arr[method] - // @ts-expect-error - if (methodFn !== arrayProto[method]) { - const result = methodFn.apply(arr, args) + + // #11759 + // If the method being called is from a user-extended Array, the arguments will be unknown + // (unknown order and unknown parameter types). In this case, we skip the shallowReadArray + // handling and directly call apply with self. + if (methodFn !== arrayProto[method as any]) { + const result = methodFn.apply(self, args) return needsWrap ? toReactive(result) : result }