Skip to content

AoT error when provider specifies useFactory with inline function #13614

Closed

Description

@mischkl

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

If a provider specifies an inline function/arrow function for useFactory, the build fails with the error 'Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function.'

For instance, the following breaks:

providers: [
    {
      provide: AuthHttp,
      deps: [Http, RequestOptions],
      useFactory: function (http: Http, options: RequestOptions) {
        return new AuthHttp(new AuthConfig(), http, options);
      }
    }
]

but changing the notation to ES6 object method shorthand works:

providers: [
    {
      provide: AuthHttp,
      deps: [Http, RequestOptions],
      useFactory(http: Http, options: RequestOptions) {
        return new AuthHttp(new AuthConfig(), http, options);
      }
    }
]

This is completely bizarre IMHO since the semantics in the above examples are identical.

Expected behavior

Should work without issue

Minimal reproduction of the problem with instructions

Only occurs when compiling using AoT, not reproducible in a plunkr.

What is the motivation / use case for changing the behavior?

Please tell us about your environment:

Windows 7, NPM 3.10.8

  • Angular version: 2.4.0 (Was not an issue under Angular 2.2.x)

  • Angular-CLI version: 1.0.0-beta.24

  • Browser: N/A

  • Language: TypeScript 2.0.10

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

Activity

  1. DzmitryShylovich commented on Dec 21, 2016

    @DzmitryShylovich
    Contributor

    ngc doesn't execute your code so it should be statically analyzable. Arrow/anonymous functions don't have a name.

    useFactory(http: Http, options: RequestOptions) {
            return new AuthHttp(new AuthConfig(), http, options);
    }
    

    is equal to

    useFactory: function useFactory(http: Http, options: RequestOptions) {
            return new AuthHttp(new AuthConfig(), http, options);
    }
    

    this is why it works

  2. DzmitryShylovich commented on Dec 21, 2016

    @DzmitryShylovich
    Contributor
  3. mischkl commented on Dec 21, 2016

    @mischkl
    Author

    Interesting.. That explains why it doesn't work. But this is incorrect behavior according to ES6 spec: http://www.2ality.com/2015/09/function-names-es6.html?m=1

    I don't know whether the problem lies with tsc or ngc but something isn't right here...

  4. mattlewis92 commented on Dec 22, 2016

    @mattlewis92
    Contributor

    Looking at the ES6 compat table, typescript doesn't seem to support them (I think it's object methods (function)): https://kangax.github.io/compat-table/es6/#typescript
    screen shot 2016-12-22 at 10 44 10

    Babel does have support for them, so I guess it's possible for typescript to as well. I'd suggest filing an issue with typescript and asking them to support function names of this type.

  5. mischkl commented on Dec 22, 2016

    @mischkl
    Author

    @mattlewis92 thanks for that. However it doesn't seem to be purely TypeScript-related, since if I use tsc (v2.0.10) to compile the following code:

    const test = {
      doSomething: function() {
        console.log(`executed function: ${this.doSomething.name}`);
      }
    }
    
    test.doSomething();

    It works as expected - the function does indeed have a name.

    Another thing worth mentioning is that even if the code is changed to fulfill the AoT requirements, it still chokes on third-party libs that have been pre-compiled with TypeScript. Case in point is https://github.com/auth0/angular2-jwt - I am attempting to use the exported AUTH_PROVIDERS in my providers. If I copy the source angular2-jwt.ts into my angular project and fix it so that useFactory has a name, everything works great. However, if I compile the source code, copy the resulting .d.ts and .js into node_modules/angular2-jwt, and import from there, it chokes with the same warning again, even though I supposedly fixed it and even though the emitted JavaScript contains the code useFactory: function useFactory(http, options)!

    The weirdest thing is that this only started happening once I upgraded to angular-cli beta.24 and angular v2.4.0. Using angular-cli beta.22 and angular v2.2.3 there was no error.

  6. mattlewis92 commented on Dec 22, 2016

    @mattlewis92
    Contributor

    That's really odd, it does seem that there have been a few internal changes that have inadvertently been breaking in 2.4

  7. added
    area: coreIssues related to the framework runtime
    on Jan 5, 2017
  8. kemsky commented on Jan 9, 2017

    @kemsky

    Any code that is referenced and uses static initialization is broken:

    class Test {
         private static field = new Value(); // Error encountered resolving symbol values statically.
    }

    However, referencing using Test['field'] does not trigger error and app works (but may broke if mangled).

    I'm loosing a lot of time with this stuff.

  9. jpduckwo commented on Jul 26, 2017

    @jpduckwo

    I'm running into this problem. For those using webpack AOT compilation the error message is the generic:

    Module not found: Error: Can't resolve './$$_gendir/app/app.module.ngfactory'

    Updating useFactory as above fixed it for me

  10. added this to the Backlog milestone on Jan 23, 2018
  11. WillHall commented on Dec 10, 2019

    @WillHall

    I was stuck on this issue for a while, so I figured I would just share what I did to get around it.

    Functions are not supported in decorators error in loadChildren solution.

    Normal Way:

    import { RouterModule, Routes } from '@angular/router';
    
    export const routes: Routes = [
      {
        path: 'mypage',
        loadChildren: () => import('@whatever/mypage').then(m => m.MyPageModule)
      }
    ]
    

    Becomes:

    import { LoadChildrenCallback, RouterModule, Routes } from '@angular/router';
    
    export const loadMyPage: LoadChildrenCallback = () => import('@whatever/mypage').then(m => m.MyPageModule);
    
    export const routes: Routes = [
      {
        path: 'mypage',
        loadChildren: loadMyPage
      }
    ]
    

    HTH googlers like me.

  12. JoostK commented on Mar 15, 2020

    @JoostK
    Member

    Support for this was added in #18390. Moreover, the Ivy compiler works a bit differently so that this is no longer an issue.

  13. added
    area: compilerIssues related to `ngc`, Angular's template compiler
    and removed
    area: coreIssues related to the framework runtime
    on Mar 15, 2020
  14. angular-automatic-lock-bot commented on Apr 15, 2020

    @angular-automatic-lock-bot

    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.

  15. locked and limited conversation to collaborators on Apr 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions