title: When using AOT, changes to objects passed to forRoot are discarded when injected
body: <h2>Overview</h2>
  
  <p>I am seeing odd behavior in that the properties that are added to an object through a destructuring assignment (or <code>Object.assign</code>) are present when passed to <code>forRoot</code> but are not present when injected into a service. Additionally, updates made after initialization are present when passed to <code>forRoot</code> but are not present when injected into a service. This only occurs when building with AOT.</p>
  
  <p>I created a minimal project that reproduces the issue:
  <a href="https://github.com/bygrace1986/wat" rel="noreferrer">https://github.com/bygrace1986/wat</a></p>
  
  <h2>Package Versions</h2>
  
  <ul>
  <li>angular: 5.2.0</li>
  <li>angular-cli: 1.6.4 (my app), 1.7.4 (my test)</li>
  <li>typescript: 2.4.2</li>
  </ul>
  
  <h2>Setup</h2>
  
  <p>Create a module that has a static <code>forRoot</code> method that will accept an object that it will then provide via an <code>InjectionToken</code> and injected into a service.</p>
  
  <p><strong>TestModule</strong></p>
  
  <pre><code>import { NgModule, ModuleWithProviders } from '@angular/core';
  import { CommonModule } from '@angular/common';
  
  import { TestDependency, TEST_DEPENDENCY, TestService } from './test.service';
  
  @NgModule({
    imports: [
      CommonModule
    ],
    declarations: []
  })
  export class TestModule {
    static forRoot(dependency?: TestDependency): ModuleWithProviders {
      return {
        ngModule: TestModule,
        providers: [
          TestService,
          { provide: TEST_DEPENDENCY, useValue: dependency }
        ]
      }
    }
  }
  </code></pre>
  
  <p><strong>TestService</strong></p>
  
  <pre><code>import { Injectable, InjectionToken, Inject } from '@angular/core';
  
  export interface TestDependency {
      property: string;
  }
  
  export const TEST_DEPENDENCY = new InjectionToken&lt;TestDependency&gt;('TEST_DEPENDENCY');
  
  @Injectable()
  export class TestService {
      constructor(@Inject(TEST_DEPENDENCY) dependency: TestDependency) {
          console.log('[TestService]', dependency);
      }
  }
  </code></pre>
  
  <h2>Non-mutated Object Scenario</h2>
  
  <p>This scenario illustrates that passing an non-mutated object to <code>forRoot</code> is properly injected into a service that depends on it.</p>
  
  <p>To setup reference the <code>TestService</code> in the <code>app.component.html</code> (or somewhere where it will be injected). Pass the dependency to the <code>forRoot</code> method on the <code>TestModule</code>.</p>
  
  <p><strong>AppModule</strong></p>
  
  <pre><code>import { BrowserModule } from '@angular/platform-browser';
  import { NgModule } from '@angular/core';
  
  import { AppComponent } from './app.component';
  import { TestModule } from './test/test.module';
  import { TestDependency } from './test/test.service';
  
  const dependency = {
    property: 'value'
  } as TestDependency;
  console.log('[AppModule]', dependency)
  
  @NgModule({
    declarations: [
      AppComponent
    ],
    imports: [
      BrowserModule,
      TestModule.forRoot(dependency)
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  </code></pre>
  
  <p>Run <code>ng serve --aot</code>.</p>
  
  <p><strong>Output</strong></p>
  
  <pre><code>[AppModule] {property: "value"}
  [TestService] {property: "value"}
  </code></pre>
  
  <h2>Mutated Object Scenario</h2>
  
  <p>This scenario illustrates that changes made to an object through object destructuring assignment during initialization or changes made after initialization are ignored when the provided object is injected into a service that depends on it.</p>
  
  <p>To setup create a new object with additional properties and use object destructuring to assign the properties of the old object to the new. Then update a property on <code>dependency</code> and pass it to the <code>forRoot</code> method on the <code>TestModule</code>.</p>
  
  <p><strong>AppModule</strong></p>
  
  <pre><code>const dependency = {
    property: 'value'
  } as TestDependency;
  const dependencyCopy = { id: 1, name: 'first', ...dependency };
  dependencyCopy.name = 'last';
  console.log('[AppModule]', dependencyCopy);
  ...
  TestModule.forRoot(dependencyCopy)
  </code></pre>
  
  <p>Run <code>ng serve --aot</code>.</p>
  
  <p><strong>Output</strong></p>
  
  <pre><code>[AppModule] {id: 1, name: "last", property: "value"}
  [TestService] {id: 1, name: "first"}
  </code></pre>
  
  <p><strong>Unexpected Result</strong></p>
  
  <p>Any property added by object destructuring assignment was removed and any update made after initialization is reverted between when the object is passed to <code>forRoot</code> and injected into <code>TestService</code>. In fact, it isn't event the same object (I debugged and checked with <code>===</code>). It is as if the original object that is created before assignment or mutation is being used... somehow.</p>
  
  <h2>Mutated Object Provided at AppModule Scenario</h2>
  
  <p>This scenario illustrates that mutations to the object are not reverted when provided at the <code>AppModule</code> level rather than through <code>forRoot</code>.</p>
  
  <p>To setup don't pass anything to <code>forRoot</code>. Instead use the injection token to provide the object in the <code>AppModule</code> providers list.</p>
  
  <p><strong>AppModule</strong></p>
  
  <pre><code>imports: [
    BrowserModule,
    TestModule.forRoot()
  ],
  providers: [
    { provide: TEST_DEPENDENCY, useValue: dependencyCopy }
  ],
  </code></pre>
  
  <p>Run <code>ng serve --aot</code>.</p>
  
  <p><strong>Output</strong></p>
  
  <pre><code>[AppModule] {id: 1, name: "last", property: "value"}
  [TestService] {id: 1, name: "last", property: "value"}
  </code></pre>
  
  <h2>Question</h2>
  
  <p>Why do changes made to an object that is provided via <code>forRoot</code> get reverted when the object is injected into a dependent class?</p>
  
  <h2>Updates</h2>
  
  <ul>
  <li>Realized that updates after initialization are also reverted.</li>
  <li>Realized that this can be reproduced with just the <code>--aot</code> flag rather than the broader <code>--prod</code> flag.</li>
  <li>Updated to latest stable cli version (1.7.4) and still have the issue.</li>
  <li>Opened a bug on the <code>angular-cli</code> project: <a href="https://github.com/angular/angular-cli/issues/10610" rel="noreferrer">https://github.com/angular/angular-cli/issues/10610</a></li>
  <li>From reading the generated code I think that the issue is in Phase 2 metadata rewriting. When only referencing the variable in <code>forRoot</code> I get this: <code>i0.ɵmpd(256, i6.TEST_DEPENDENCY, { id: 1, name: "first" }, [])]);</code>. When it is referenced in the <code>AppModule</code> provider list I get this: <code>i0.ɵmpd(256, i6.TEST_DEPENDENCY, i1.ɵ0, [])]);</code> and then this in the app module <code>var ɵ0 = dependencyCopy; exports.ɵ0 = ɵ0;</code>.</li>
  </ul>