Repository: vuejs/vue
Pull request: Merge inject when extending a component

<!--
Please make sure to read the Pull Request Guidelines:
https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines
-->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->
[#5603](https://github.com/vuejs/vue/issues/5603)

**What kind of change does this PR introduce?** (check at least one)

- [ ] Bugfix
- [x] 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
- [x] 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:**


Changed files:
filename: src/core/instance/inject.js
patch: @@ -38,18 +38,14 @@ export function initInjections (vm: Component) {
 export function resolveInject (inject: any, vm: Component): ?Object {
   if (inject) {
     // inject is :any because flow is not smart enough to figure out cached
-    // isArray here
-    const isArray = Array.isArray(inject)
     const result = Object.create(null)
-    const keys = isArray
-      ? inject
-      : hasSymbol
+    const keys = hasSymbol
         ? Reflect.ownKeys(inject)
         : Object.keys(inject)
 
     for (let i = 0; i < keys.length; i++) {
       const key = keys[i]
-      const provideKey = isArray ? key : inject[key]
+      const provideKey = inject[key]
       let source = vm
       while (source) {
         if (source._provided && provideKey in source._provided) {

filename: src/core/util/options.js
patch: @@ -182,6 +182,7 @@ strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object {
  */
 strats.props =
 strats.methods =
+strats.inject =
 strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object {
   if (!childVal) return Object.create(parentVal || null)
   if (!parentVal) return childVal
@@ -247,6 +248,19 @@ function normalizeProps (options: Object) {
   options.props = res
 }
 
+/**
+ * Normalize all injections into Object-based format
+ */
+function normalizeInject (options: Object) {
+  const inject = options.inject
+  if (Array.isArray(inject)) {
+    const normalized = options.inject = {}
+    for (let i = 0; i < inject.length; i++) {
+      normalized[inject[i]] = inject[i]
+    }
+  }
+}
+
 /**
  * Normalize raw function directives into object format.
  */
@@ -280,6 +294,7 @@ export function mergeOptions (
   }
 
   normalizeProps(child)
+  normalizeInject(child)
   normalizeDirectives(child)
   const extendsFrom = child.extends
   if (extendsFrom) {

filename: test/unit/features/options/inject.spec.js
patch: @@ -220,6 +220,35 @@ describe('Options provide/inject', () => {
     })
   })
 
+  it('should extend properly', () => {
+    const parent = Vue.extend({
+      template: `<span/>`,
+      inject: ['foo']
+    })
+
+    const child = parent.extend({
+      template: `<span/>`,
+      inject: ['bar'],
+      created () {
+        injected = [this.foo, this.bar]
+      }
+    })
+
+    new Vue({
+      template: `<div><parent/><child/></div>`,
+      provide: {
+        foo: 1,
+        bar: false
+      },
+      components: {
+        parent,
+        child
+      }
+    }).$mount()
+
+    expect(injected).toEqual([1, false])
+  })
+
   it('should warn when injections has been modified', () => {
     const key = 'foo'
     const vm = new Vue({