Skip to content

Add support for arrow functions - #66294

Merged
thePunderWoman merged 9 commits into
angular:mainfrom
crisbeto:arrow-fn
Jan 9, 2026
Merged

thePunderWoman merged 9 commits into
angular:mainfrom
crisbeto:arrow-fn

Conversation

@crisbeto

@crisbeto crisbeto commented Jan 2, 2026 •

Copy link
Copy Markdown
Member

Adds support for using arrow functions in Angular expressions. They generally behave like JS arrow functions with the same access as other Angular expressions, but with the following limitations:

  • We only support arrow functions with implicit returns, e.g. (a) => a + 1 is allowed while (a) => { return a + 1 } is not.
  • Pipes can't be used inside arrow functions, but they can be passed through to pipes.

To avoid recreating the functions in each change detection, the compiler generates an instruction that caches the function after it's referenced for the first time.

Fixes #14129.

@crisbeto crisbeto added action: review The PR is still awaiting reviews from at least one requested reviewer target: minor This PR is targeted for the next minor release labels Jan 2, 2026
@angular-robot angular-robot Bot added detected: feature PR contains a feature commit area: compiler Issues related to `ngc`, Angular's template compiler area: core Issues related to the framework runtime labels Jan 2, 2026
@ngbot ngbot Bot modified the milestone: Backlog Jan 2, 2026
@crisbeto
crisbeto marked this pull request as ready for review January 2, 2026 13:30
Comment on lines +3328 to +3329
template: `<button (click)="value.update(prev => prev + 1)">Increment</button>`,
})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you given any thoughts of what we might want to do when users write (click)="() => { ... }".
I could see that happening because of how events handlers are written in JSX.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean supporting an arrow function that returns an object literal?

@JeanMeche JeanMeche Jan 2, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was more thiking about the cases where users write an uninvoked arrow function passed to a template event listener.

(click)="() => mySignal.set(0)"

will result in a noop and it might catch developers of guard.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see. Seems like a good candidate for an extended diagnostic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this perhaps also a chance to get rid of the magic $event in event bindings?

I'm thinking on

(event) => doStuff(event)

vs.

doStuff($event);

@crisbeto

crisbeto commented Jan 9, 2026

Copy link
Copy Markdown
Member Author

Passing TGP

Adds some logic to tokenize the `=>` character combination in the lexer.
Expands the expression AST to include arrow functions.
Updates the expression parser to handle arrow functions. Since arrow functions share syntax with other AST nodes, we have to detect them by looking ahead and then potentially jumping backwards depending on what we see.
…tions

Updates the template type checker to support arrow functions. The main challenge was getting the current infrastructure not to rewrite references to arrow function parameters.
Adds the `ɵɵstoreCallback` instruction that allows for a callback to be stored for later usage, as well as `ɵɵgetCallback` which can be used to retrieve it.
The `countVariables` phase visits all ops in the list and all nested expressions in order to count how many variables are used. Currently it does so by going through `unit.ops()` and then calling `visitExpressionsInOp` on each op.

This leads to expressions in ops that have nested ops (e.g. `ListenerOp`) to be visited twice, because `unit.ops()` descends into child ops and then `visitExpressionsInOp` does the same. It hasn't been a problem so far, because the only expressions that can have vars in host bindings are pure functions and they aren't generated for listeners, but it will become a problem for arrow functions since they can be used in listeners.

These changes resolve the issue by iterating over the `unit.create` and `unit.update` instead.
Adds support for using arrow functions in Angular expressions. They generally behave like JS arrow functions with the same access as other Angular expressions, but with the following limitations:
* We only support arrow functions with implicit returns, e.g. `(a) => a + 1` is allowed while `(a) => { return a + 1 }` is not.
* Pipes can't be used inside arrow functions, but they can be passed through to pipes.

To avoid recreating the functions in each change detection, the compiler applies a couple of optimizations:
* If an arrow function only references its own parameters, it is extracted into a top-level constant that is passed around to the different usage sites.
* If an arrow function has references to the template context, we store it on the current view and read the stored value later on.

Fixes angular#14129.
Reworks how we store arrow functions in the following ways:
1. Rather than the `storeCallback` and `getCallback` instructions, we generate a single `arrowFunction` instruction.
2. The `arrowFunction` instruction uses a factory to create a new instance of the function when a function is read for the first time.
3. We now keep arrow functions in listeners in line so that they have access to `$event`.
Isolates the logic that fixes references to arrow function parameters so that we don't have do pass extra parameters for every `convertAst` call.
@crisbeto crisbeto added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jan 9, 2026
@thePunderWoman
thePunderWoman merged commit 7b5625e into angular:main Jan 9, 2026
20 checks passed
@thePunderWoman

Copy link
Copy Markdown
Contributor

This PR was merged into the repository. The changes were merged into the following branches:

@toverux

toverux commented Jan 9, 2026

Copy link
Copy Markdown

Wow, just a thank you for implementing this almost-a-decade-old feature request! That will be very nice for QoL.

@JeanMeche

Copy link
Copy Markdown
Member

FYI this was merged in the branch for v21.2 which will be released mid-febuary.

crisbeto added a commit to crisbeto/angular that referenced this pull request Feb 5, 2026
… listeners

Based on the discussion in angular#66294: now that we support arrow functions in event listeners, developers may write out something like `(click)="() => expr"` which will be a no-op. These changes update the existing diagnostic for uninvoked expressions in listeners to account for it.
AndrewKushnir pushed a commit that referenced this pull request Feb 6, 2026
… listeners

Based on the discussion in #66294: now that we support arrow functions in event listeners, developers may write out something like `(click)="() => expr"` which will be a no-op. These changes update the existing diagnostic for uninvoked expressions in listeners to account for it.
AndrewKushnir pushed a commit that referenced this pull request Feb 6, 2026
… listeners

Based on the discussion in #66294: now that we support arrow functions in event listeners, developers may write out something like `(click)="() => expr"` which will be a no-op. These changes update the existing diagnostic for uninvoked expressions in listeners to account for it.

(cherry picked from commit 2ea6dfc)
@angular-automatic-lock-bot

Copy link
Copy Markdown

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 Feb 9, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: compiler Issues related to `ngc`, Angular's template compiler area: core Issues related to the framework runtime detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support arrow functions in template syntax

5 participants