Browse Source

fix(reactivity): correctly handle method calls on user-extended arrays (#11760)

close #11759
Tycho 1 year ago
parent
commit
9817c80187

+ 21 - 0
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' })
+      }
     })
   })
 })

+ 7 - 3
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
   }