angular: AoT error with `@Inject` and interface type

I’m submitting a … (check one with “x”)

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

I have a constructor that uses @Inject to get a dependency, and references an interface for that the dep, constructor( @Inject(FirebaseApp) _fbApp: firebase.app.App). When I compile the lib with ngc, I get this error:

Error: angularfire2/src/auth/firebase_sdk_auth_backend.ts:27:1: Error encountered in metadata generated for exported symbol 'FirebaseSdkAuthBackend':
 angularfire2/src/auth/firebase_sdk_auth_backend.ts:30:45: Metadata collected contains an error that will be reported at runtime: Expression form not supported.
  {"__symbolic":"error","message":"Expression form not supported","line":29,"character":44}
    at angularfire2/node_modules/@angular/tsc-wrapped/src/collector.js:514:27
    at Array.forEach (native)
    at validateMetadata (angularfire2/node_modules/@angular/tsc-wrapped/src/collector.js:502:42)
    at MetadataCollector.getMetadata (angularfire2/node_modules/@angular/tsc-wrapped/src/collector.js:374:17)
    at MetadataWriterHost.writeMetadata (angularfire2/node_modules/@angular/tsc-wrapped/src/compiler_host.js:111:51)
    at MetadataWriterHost.writeFile (angularfire2/node_modules/@angular/tsc-wrapped/src/compiler_host.js:103:19)
    at Object.writeFile (angularfire2/node_modules/typescript/lib/typescript.js:45364:132)
    at Object.writeFile (angularfire2/node_modules/typescript/lib/typescript.js:7597:14)
    at writeEmittedFiles (angularfire2/node_modules/typescript/lib/typescript.js:37854:20)
    at doEmit (angularfire2/node_modules/typescript/lib/typescript.js:37714:17)

If I change the type to any, compilation succeeds.

Expected behavior

I would expect to be able to reference an interface in a constructor in conjunction with @Inject.

Minimal reproduction of the problem with instructions

ngc this thing:

import { NgModule, Inject, Injectable } from '@angular/core';
import { Http } from '@angular/http';

export interface Foo {}

@Injectable()
export class MyClass {
  constructor(@Inject(Http) http: Foo) {}
}

@NgModule({
  providers: [MyClass]
})
export class MyModule {}


  • Angular version: 2.0.X

@angular/compiler-cli@2.1.2 @angular/core@2.1.2

  • Node (for AoT issues): node --version =

Node 5.10.1

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 21
  • Comments: 40 (16 by maintainers)

Commits related to this issue

Most upvoted comments

@MadUser looks like it doesn’t work with ts interfaces such as Window, Document etc. See https://github.com/angular/angular/issues/15640

@skdhir for example:

private window: Window;
constructor(@Inject('Window') window: any) {
   this.window = window as Window;
}

I am having this as well.

This fails with AoT compiler in Angular CLI, because Window (the browser window) is an interface:

export function getWindow() { return window; }

@NgModule({
  declarations: [
    AppComponent,
    SimpleRouteComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRoutingModule
  ],
  providers: [
    {provide: 'window', useFactory: getWindow}
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
  constructor(@Inject('window') w: Window) {
    console.log(w);
  }
}

With error:

ERROR in Error encountered resolving symbol values statically. Could not resolve type Window (position 29:36 in the original .ts file), resolving symbol AppModule in /Users/Meligy/Code/github/Meligy/routing-angular-cli/src/app/app.module.ts

(More details in #14050)

The workaround (other than using any type in the constructor) was to create a dummy class type to trick the compiler, like:

@Injectable()
export class WindowWrapper extends Window {

}

export function getWindow() { return window; }

@NgModule({
  declarations: [
    AppComponent,
    SimpleRouteComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRoutingModule
  ],
  providers: [
    {provide: WindowWrapper, useFactory: getWindow}
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
  constructor(w: WindowWrapper) {
    console.log(w);
  }
}

Still happening on v2.4.4. Trying to inject angular’s DOCUMENT token:

import { Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

@Injectable()
export class MyService {
  constructor(
    @Inject(DOCUMENT) doc: Document // <-- This fails with ngc =(
  ) { }
}

@dscheerens see my version of this in this https://github.com/angular/angular/issues/12631#issuecomment-274260009. In TypeScript, a class can say it extends an interface rather than implements it, which does not require the class to repeat the interface members.