Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ngFor over functions causes type error with Ivy #39634

Closed
ersimont opened this issue Nov 11, 2020 · 7 comments
Closed

ngFor over functions causes type error with Ivy #39634

ersimont opened this issue Nov 11, 2020 · 7 comments
Assignees
Labels
area: compiler Issues related to `ngc`, Angular's template compiler compiler: template type-checking P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: confirmed state: has PR
Milestone

Comments

@ersimont
Copy link

ersimont commented Nov 11, 2020

🐞 bug report

Affected Package

@angular/common, maybe? It's a compile-time error using nothing special except *ngFor

Is this a regression?

This appeared as I was upgrading from Angular 9.1.0, though @JoostK below (#39634 (comment)) was able to reproduce it on the latest 9.0.x and 9.1.x.

Description

When looping over an array of functions using *ngFor, a strange typing error occurs when calling that function in the template. For example in this template it gives an error like the following:

export class AppComponent  {
  functions = [() => 1, () => 2];
}

<p *ngFor="let fn of functions">
	{{ fn() }}
</p>

Property 'fn' does not exist on type '() => number'.

You'll see that it somehow is trying to find fn on the function itself? It works fine if you turn off Ivy.

🔬 Minimal Reproduction

https://stackblitz.com/edit/angular-ivy-vttvch?file=src/app/app.component.html

🔥 Exception or Error

Property '__' does not exist on type '___'.

🌍 Your Environment

Angular Version:


Angular CLI: 10.2.0
Node: 12.18.1
OS: win32 x64

Angular: 10.2.2
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router, service-worker
Ivy Workspace: Yes

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1002.0
@angular-devkit/build-angular   0.1002.0
@angular-devkit/core            10.2.0
@angular-devkit/schematics      10.2.0
@angular/cdk                    10.2.7
@angular/cli                    10.2.0
@angular/material               10.2.7
@schematics/angular             10.2.0
@schematics/update              0.1002.0
rxjs                            6.6.3
typescript                      4.0.5

Anything else relevant?
Must be using ivy

@zero-1
Copy link

zero-1 commented Nov 11, 2020

Not really relevant.... but you should try to not call methods from the template....

Here is a fix though...

functions = [
(() => 1)(),
(() => 2)()
];

{{ fn }}

@AndrewKushnir AndrewKushnir added area: compiler Issues related to `ngc`, Angular's template compiler compiler: template type-checking labels Nov 11, 2020
@ngbot ngbot bot modified the milestone: needsTriage Nov 11, 2020
@JoostK JoostK added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: confirmed labels Nov 11, 2020
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Nov 11, 2020
@JoostK
Copy link
Member

JoostK commented Nov 11, 2020

Confirmed as broken, but does not appear to be a (recent) regression. Latest 9.0.x and 9.1.x also produce the same error.

@ersimont
Copy link
Author

Oh that's a surprise - sorry for the misinformation. This appeared as I was upgrading from 9.1 to 10! I'll update the description.

@AleksanderBodurri
Copy link
Member

Not really relevant.... but you should try to not call methods from the template....

Here is a fix though...

functions = [
(() => 1)(),
(() => 2)()
];

{{ fn }}

@zero-1
There's nothing wrong with calling methods from the template as long as the time complexity of the method is reasonable. Any method with linear time complexity or better that is run from the template is usually fine.

@ersimont

Here are some possible work arounds for now until this is fixed,

Workaround 1.

export class AppComponent  {
  functions = [() => 1, () => 2];
}
<p *ngFor="let fn of functions">
	{{ fn.call(this) }}
</p>

Workaround 2.

export class AppComponent  {
  functions = [() => 1, () => 2];

  eval(method: Function): number {
    return method();
  }
}
<p *ngFor="let fn of functions">
	{{ eval(fn) }}
</p>

@ersimont
Copy link
Author

@AleksanderBodurri Nice ideas. Thank you, that workaround unblocks me for now!

@AleksanderBodurri
Copy link
Member

@ersimont

No worries.

Another possible workaround that I missed,

<p *ngFor="let fn of functions">
	{{ (fn)() }}
</p>

@crisbeto crisbeto self-assigned this Nov 14, 2020
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 14, 2020
…te variables

Currently when we encounter an implicit method call (e.g. `{{ foo(1) }}`) and we manage to resolve
its receiver to something within the template, we assume that the method is on the receiver itself
so we generate a type checking code to reflect it. This assumption is true in most cases, but it
breaks down if the call is on an implicit receiver and the receiver itself is being invoked. E.g.

```
<div *ngFor="let fn of functions">{{ fn(1) }}</div>
```

These changes resolve the issue by generating a regular function call if the method call's receiver
is pointing to `$implicit`.

Fixes angular#39634.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 15, 2020
…te variables

Currently when we encounter an implicit method call (e.g. `{{ foo(1) }}`) and we manage to resolve
its receiver to something within the template, we assume that the method is on the receiver itself
so we generate a type checking code to reflect it. This assumption is true in most cases, but it
breaks down if the call is on an implicit receiver and the receiver itself is being invoked. E.g.

```
<div *ngFor="let fn of functions">{{ fn(1) }}</div>
```

These changes resolve the issue by generating a regular function call if the method call's receiver
is pointing to `$implicit`.

Fixes angular#39634.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 15, 2020
…te variables

Currently when we encounter an implicit method call (e.g. `{{ foo(1) }}`) and we manage to resolve
its receiver to something within the template, we assume that the method is on the receiver itself
so we generate a type checking code to reflect it. This assumption is true in most cases, but it
breaks down if the call is on an implicit receiver and the receiver itself is being invoked. E.g.

```
<div *ngFor="let fn of functions">{{ fn(1) }}</div>
```

These changes resolve the issue by generating a regular function call if the method call's receiver
is pointing to `$implicit`.

Fixes angular#39634.
atscott pushed a commit that referenced this issue Nov 16, 2020
…te variables (#39686)

Currently when we encounter an implicit method call (e.g. `{{ foo(1) }}`) and we manage to resolve
its receiver to something within the template, we assume that the method is on the receiver itself
so we generate a type checking code to reflect it. This assumption is true in most cases, but it
breaks down if the call is on an implicit receiver and the receiver itself is being invoked. E.g.

```
<div *ngFor="let fn of functions">{{ fn(1) }}</div>
```

These changes resolve the issue by generating a regular function call if the method call's receiver
is pointing to `$implicit`.

Fixes #39634.

PR Close #39686
@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: compiler Issues related to `ngc`, Angular's template compiler compiler: template type-checking P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: confirmed state: has PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants