Repository: vuejs/vue
Pull request: Allow named properties on reactive arrays.

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [x] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [x] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [x] New/updated tests are included

If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

**Other information:**

Since arrays can be treated as normal objects in JavaScript and contain a mix of numeric and named properties, this patch makes `Vue.set` and `Vue.del` deal correctly with named properties on reactive arrays.

Changed files:
filename: src/core/observer/index.js
patch: @@ -189,7 +189,7 @@ export function defineReactive (
  * already exist.
  */
 export function set (target: Array<any> | Object, key: any, val: any): any {
-  if (Array.isArray(target)) {
+  if (Array.isArray(target) && typeof key === 'number') {
     target.length = Math.max(target.length, key)
     target.splice(key, 1, val)
     return val
@@ -198,7 +198,7 @@ export function set (target: Array<any> | Object, key: any, val: any): any {
     target[key] = val
     return val
   }
-  const ob = target.__ob__
+  const ob = (target : any).__ob__
   if (target._isVue || (ob && ob.vmCount)) {
     process.env.NODE_ENV !== 'production' && warn(
       'Avoid adding reactive properties to a Vue instance or its root $data ' +
@@ -219,11 +219,11 @@ export function set (target: Array<any> | Object, key: any, val: any): any {
  * Delete a property and trigger change if necessary.
  */
 export function del (target: Array<any> | Object, key: any) {
-  if (Array.isArray(target)) {
+  if (Array.isArray(target) && typeof key === 'number') {
     target.splice(key, 1)
     return
   }
-  const ob = target.__ob__
+  const ob = (target : any).__ob__
   if (target._isVue || (ob && ob.vmCount)) {
     process.env.NODE_ENV !== 'production' && warn(
       'Avoid deleting properties on a Vue instance or its root $data ' +

filename: test/unit/modules/observer/observer.spec.js
patch: @@ -284,6 +284,17 @@ describe('Observer', () => {
     delProp(obj3, 'a')
     expect(hasOwn(obj3, 'a')).toBe(false)
     expect(dep3.notify.calls.count()).toBe(2)
+    // set and delete non-numeric key on array
+    const arr2 = ['a']
+    const ob2 = observe(arr2)
+    const dep2 = ob2.dep
+    spyOn(dep2, 'notify')
+    setProp(arr2, 'b', 2)
+    expect(arr2.b).toBe(2)
+    expect(dep2.notify.calls.count()).toBe(1)
+    delProp(arr2, 'b')
+    expect(hasOwn(arr2, 'b')).toBe(false)
+    expect(dep2.notify.calls.count()).toBe(2)
   })
 
   it('warning set/delete on a Vue instance', done => {