Angular-cli: Running `ng test` fails with Uncaught ReferenceError: [TYPE_NAME] is not defined

Created on 25 Mar 2017  Â·  26Comments  Â·  Source: angular/angular-cli

Bug Report or Feature Request (mark with an x)

- [X] bug report -> please search issues before submitting
- [ ] feature request

Versions.

$ ng --version
    _                      _                 ____ _     ___
   / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
  / â–³ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
 / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
/_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
               |___/
@angular/cli: 1.0.0
node: 6.9.1
os: win32 x64
@angular/common: 4.0.0
@angular/compiler: 4.0.0
@angular/core: 4.0.0
@angular/forms: 4.0.0
@angular/http: 4.0.0
@angular/platform-browser: 4.0.0
@angular/platform-browser-dynamic: 4.0.0
@angular/router: 4.0.0
@angular/cli: 1.0.0
@angular/compiler-cli: 4.0.0

Windows 10

Repro steps.

Step 1
Run the following command

ng new myapp

Step 2
Add following file MyType.ts in the folder where the generate app.conponent.ts is located.

export class MyType {
    constructor(public id: string){}
}

Step 3
Modify app.conponent.ts so it looks like this:

import { Component, Input } from '@angular/core';
import { MyType } from "app/MyType";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';

  private selectedId: string;
  @Input() set setSelectedId(myType: MyType | undefined) {
    if (product !== undefined) {
      this.selectedId = myType.id;
    }
    else {
      this.selectedId = myType;
    }
  }
}

Step 4
Run the following command

ng test

The log given by the failure.

Result:

$ ng test
25 03 2017 07:37:40.092:WARN [karma]: No captured browser, open http://localhost:9876/
25 03 2017 07:37:40.107:INFO [karma]: Karma v1.4.1 server started at http://0.0.0.0:9876/
25 03 2017 07:37:40.108:INFO [launcher]: Launching browser Chrome with unlimited concurrency
25 03 2017 07:37:40.185:INFO [launcher]: Starting browser Chrome
25 03 2017 07:37:41.275:INFO [Chrome 57.0.2987 (Windows 10 0.0.0)]: Connected on socket 9t52BW0h_NVdN1zYAAAA with id 31811334
Chrome 57.0.2987 (Windows 10 0.0.0) ERROR
  Uncaught ReferenceError: MyType_1 is not defined
  at webpack:///src/app/app.component.ts:13:43 <- src/test.ts:52770

Chrome 57.0.2987 (Windows 10 0.0.0) ERROR
  Uncaught ReferenceError: MyType_1 is not defined
  at webpack:///src/app/app.component.ts:13:43 <- src/test.ts:52770

Desired functionality.

I would like to to have the test being run :)

Mention any other details that might be useful.

App is working fine, so it seems to be only when running tests. I know that it worked in version 2.x of the cli and Im pretty sure it is related to the typescript version, where it worked with TS 2.0.x and not with TS 2.2.x.

Alto, it works if @Input is not used and app.component.ts looks this:

import { Component } from '@angular/core';
import { MyType } from "app/MyType";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';

  private selectedId: string;
  set setSelectedId(myType: MyType | undefined) {
    if (product !== undefined) {
      this.selectedId = myType.id;
    }
    else {
      this.selectedId = myType;
    }
  }
}

Most helpful comment

I had this problem not with the test but the main code itself when I upgraded from Angular 4.3.0 to 5.2.9 and Angular Material from 2.0.0-beta-2 to 5.2.4. The problem was an @Injected service inside a parent component.

export abstract class ParentComponent {
    constructor(@Inject(WhateverService) protected service: WhateverService,
            protected dialog: MatDialog, protected error: Error) { }
}

---

export class ChildComponent extends ParentComponent {
    constructor(service: WhateverService, dialog: MatDialog, error: Error) {
        super(service, dialog);
    }
}

That was giving the error:

ERROR Error: Uncaught (in promise): ReferenceError: material_1 is not defined
ReferenceError: material_1 is not defined

As wrong as it might look, it was working with the older versions.

Well, investigating the transpiled js, I saw that the material_1 was for the dialog and I spent hours in that parameter. Until I saw that if I put the MatDialog parameter first, the problem was transferred to the third parameter. That's when I realized that the problem was with the service. So the solution for me was to put the @Inject annotation into the ChildCompoment (which makes more sense).

export abstract class ParentComponent {
    constructor(protected service: WhateverService,
            protected dialog: MatDialog, protected error: Error) { }
}

---

export class ChildComponent extends ParentComponent {
    constructor(@Inject(WhateverService) service: WhateverService,
            dialog: MatDialog, error: Error) {
        super(service, dialog);
    }
}

And now it's working fine. Well, it might be a little unrelated to the issues you are reporting, but I hope it helps you to find the solution to your environment.

All 26 comments

Same issue here, it seems to be related to using typescript union types in method signatures, either @Input or constructor in my case

Further investigation leads me to the direction of metadata reflection combined with interface unions, however I'm still stumped on a solution

Another update. So I was able to find a temporary fix - in tsconfig.spec.json, change module to es2015 and target to es6. Mine looks like:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/spec",
    "module": "es2015",
    "target": "es6",
    "baseUrl": "",
    "types": [
      "jasmine",
      "node",
      "faker"
    ]
  },
  "files": [
    "test.ts"
  ],
  "include": [
    "**/*.spec.ts",
    "**/*.d.ts"
  ]
}

This does not fix the issue however, as switching to targeting es6 is obviously risky when runtime uses es5, and it also breaks the coverage reporter completely.

Same issue here. My testing matches yours in that it is caused by a combination of @ Input() with union types. The latest version of typescript that works for me is 2.1.4

My repro steps can repro this issue without using discriminated union types.

@IngvarKofoed the one in your description of the original issue? That has method signature set setSelectedId(myType: MyType | undefined). Unless you mean another repro?

@zakhenry Oh yea, totally did not see that, sorry :)

Getting the same issue here....
Updating tsconfig.spec.json as suggested by @zakhenry (module="es2015") does resolve the issue for running ng test.

However, this completely breaks code coverage collection (ng test --cc).
I've created a separate issue to track this bug: https://github.com/angular/angular-cli/issues/6142

Any solutions other than the suggested module change?

Using module="es2015" isn't a real fix for the problem at hand, your browser might understand ES2015 modules but tooling (like the code coverage karma reporter) might not support it. This resulted in @orazyto's #6142.

I don't have another solution myself to be honest, nor do I know if it's a problem with the CLI or with Typescript. @sumitarora will investigate.

I was able to replicate this issue outside of any angular-cli usage.

I have an angular application using webpack 2.5.1, typescript 2.3.2, and angular 4.1.0. If I have an @Input() decorated property and put it in a type union with "| null", then the modules built by webpack end up producing this error because they aren't including the module for the primary object type in the union.

I don't have a minimal replication yet, but removing the "| null" causes the issue to go away.

@zakhenry @filipesilva I was just able to fix mine but doing something a bit crazy. I realized that components where I have an object (ex: MyObj) as an @Input parameter type but where I don't use the type in the code in the module are the only modules giving me issues. So I added a usage of the type in the module and the issues goes away.

So if you have 'MyObj' as the type for the @Input with null, try adding a protected method to the component that simply returns a new instance of that type. Doesn't have to be called, just has to use the type. Once I did that it worked again.

Example:

class MyComp {
   @Input() myObj: MyObj | null = null;

   protected _notCalled(): any {
      return new MyObj();
   }
}

Crazy hack I know, but it worked for me.

did anyone else find a real fix or any details on the underlying issue?

If this helps, here's what I debugged so far from this particular code:

import { MenuPositionX, MenuPositionY } from '@angular/material';

export class FooComponent {
  private _xPosition: MenuPositionX = 'after';
  ...
}

In an es2015 output with es6 target obviously it'll output a normal class declaration with the methods declared as:

...
constructor() {
  this._xPosition = 'after';
  ...
}

This is close to what production build would output, but as a function declaration:

function FooComponent() {
  this._xPosition = 'after';
  ...
}

But then this is what tsconfig.spec.json would generate with commonjs and es5:

__decorate([
    core_1.Input(),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [typeof (_b = typeof material_1.MenuPositionX !== "undefined" && material_1.MenuPositionX) === "function" && _b || Object])
], FooComponent.prototype, "xPosition", null);

This results in:

Chrome 61.0.3141 (Mac OS X 10.12.4) ERROR
  Uncaught ReferenceError: material_1 is not defined
  at http://localhost:9876/_karma_webpack_/main.bundle.js:4584

If I have to assume (with my limited TS compiler and Karma knowledge), this is the output of decorators from experimentalDecorators actually wanting to do a type check for MenuPositionX, but I don't think this information gets passed through Webpack to make sure that material_1 or @angular/material gets required by Webpack.

A configuration of es2015 and es5 (which I assume is just like production) returns this:

__decorate([
    __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["c" /* Input */])(),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [typeof (_b = typeof MenuPositionX !== "undefined" && MenuPositionX) === "function" && _b || Object])
], FooComponent.prototype, "xPosition", null);

Notice how this __decorate call is different compared to when the type is actually imported in:

__decorate([
    __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_13" /* ViewChild */])('rawContent'),
    __metadata("design:type", typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_0__angular_core__["m" /* ElementRef */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_0__angular_core__["m" /* ElementRef */]) === "function" && _a || Object)
], BarComponent.prototype, "rawContent", void 0);

That's for a @ViewChild('rawContent') rawContent: ElementRef.

I'm assuming this has to do with how the logic on Webpack for tests when it comes to loading dependencies has to do with "if it's just loading a dependency for the type checks, don't"?

I am still running into this in quite a few places in our code. Has anyone found a reported bug in webpack, typescript, or elsewhere that would fix this finally?

+1

@Brocco can you take a look?

We solved this by including our global scripts in the assets folder. We
then found we needed to register them with the CLI, karma.config, and
include them as an import in index.html.

We were struggling with these issues for a while, as we use global scripts
to handle environment specific variables n CI. When this story came out in
the docs https://github.com/angular/angular-cli/wiki/stories-global-scripts
I followed it to a tee, but found it didn't work. We still had to register
globals in index.html.

On Wed, Jul 5, 2017, 2:41 PM Allen notifications@github.com wrote:

I am still running into this in quite a few places in our code. Has anyone
found a reported bug in webpack, typescript, or elsewhere that would fix
this finally?

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular-cli/issues/5651#issuecomment-313205626,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADQeYkJjYVnNXm4cN19SbFQ51EJJoc1dks5sK-blgaJpZM4Mo_V2
.

As of the most recent cli version 3, we found duplicate declarations having globals referenced in index.html, karma.config and angular-cli.json. it appears the cli is in fact now bundling them. Removing them from the index and karma.config does the trick of removing the duplicate reference errors.

I had the same issue initially with ng test as was provided in the description. It was fixed by changing module and target to es2015 and es6 appropriately . But after upgrading to ng 5.x even this fix stopped working + JIT compilation stopped working with the same error as well...

The another workaround for me was assigning the type which causes this error to any variable before class definition. With this fix everything started working even with initial module=commonjs ad target=es5. Here is an example:

import {MyIssueService} from 'path_to_service';
[other imports]

const hack = MyIssueService;
export class ConsumerClass {
   constructor(private service: MyIssueService) {
   }
   ...
}

I had this problem not with the test but the main code itself when I upgraded from Angular 4.3.0 to 5.2.9 and Angular Material from 2.0.0-beta-2 to 5.2.4. The problem was an @Injected service inside a parent component.

export abstract class ParentComponent {
    constructor(@Inject(WhateverService) protected service: WhateverService,
            protected dialog: MatDialog, protected error: Error) { }
}

---

export class ChildComponent extends ParentComponent {
    constructor(service: WhateverService, dialog: MatDialog, error: Error) {
        super(service, dialog);
    }
}

That was giving the error:

ERROR Error: Uncaught (in promise): ReferenceError: material_1 is not defined
ReferenceError: material_1 is not defined

As wrong as it might look, it was working with the older versions.

Well, investigating the transpiled js, I saw that the material_1 was for the dialog and I spent hours in that parameter. Until I saw that if I put the MatDialog parameter first, the problem was transferred to the third parameter. That's when I realized that the problem was with the service. So the solution for me was to put the @Inject annotation into the ChildCompoment (which makes more sense).

export abstract class ParentComponent {
    constructor(protected service: WhateverService,
            protected dialog: MatDialog, protected error: Error) { }
}

---

export class ChildComponent extends ParentComponent {
    constructor(@Inject(WhateverService) service: WhateverService,
            dialog: MatDialog, error: Error) {
        super(service, dialog);
    }
}

And now it's working fine. Well, it might be a little unrelated to the issues you are reporting, but I hope it helps you to find the solution to your environment.

So the solution for me was to put the @Inject annotation into the ChildCompoment (which makes more sense).

Thanks to your reply, I found my bug: I accidently added an Inject() annotation in the constructor of an abstract base class for my components. Removing it solved this issue.

@kleber-swf YOU ARE MY HERO <3 Actually, putting @Injectable on top of the class with mixed @Inject/non-@Inject constructor solved the problem as well!

Hi guys,
I just found a workaround create a type alias type MyTypeOptional = MyType | undefined; and use it in the @Input , it should work.

I'm sorry, but we can't reproduce the problem following the instructions you provided.
Remember that we have a large number of issues to resolve, and have only a limited amount of time to reproduce your issue.
Short, explicit instructions make it much more likely we'll be able to reproduce the problem so we can fix it.

If the problem persists, please open a new issue following our submission guidelines.

A good way to make a minimal repro is to create a new app via ng new repro-app and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings