Skip to content

fix(compiler-cli): check event side of two-way bindings#59002

Closed
crisbeto wants to merge 3 commits intoangular:mainfrom
crisbeto:58971/two-way-binding-checking
Closed

fix(compiler-cli): check event side of two-way bindings#59002
crisbeto wants to merge 3 commits intoangular:mainfrom
crisbeto:58971/two-way-binding-checking

Conversation

@crisbeto
Copy link
Copy Markdown
Member

@crisbeto crisbeto commented Dec 2, 2024

In the past two-way bindings used to be interpreted as foo = $event at the parser level. In #54065 it was changed to preserve the actual expression, because it was problematic for supporting two-way binding to signals. This unintentionally ended up causing the TCB to two-way bindings to look something like someOutput.subscribe($event => expr); which does nothing. It largely hasn't been a problem, because the input side of two-way bindings was still being checked, except for the case where the input side of the two-way binding has a wider type than the output side.

These changes re-add type checking for the output side by generating the following TCB instead:

someOutput.subscribe($event => {
  var _t1 = unwrapSignalValue(this.someField);
  _t1 = $event;
});

@crisbeto crisbeto added target: minor This PR is targeted for the next minor release action: global presubmit The PR is in need of a google3 global presubmit labels Dec 2, 2024
@crisbeto crisbeto force-pushed the 58971/two-way-binding-checking branch from ea73ddb to 713a598 Compare December 2, 2024 10:20
The `isSplitTwoWayBinding` function was a bit misleading, because it has side effects. Renames the function make it a bit more explicit.
In the past two-way bindings used to be interpreted as `foo = $event` at the parser level. In angular#54065 it was changed to preserve the actual expression, because it was problematic for supporting two-way binding to signals. This unintentionally ended up causing the TCB to two-way bindings to look something like `someOutput.subscribe($event => expr);` which does nothing. It largely hasn't been a problem, because the input side of two-way bindings was still being checked, except for the case where the input side of the two-way binding has a wider type than the output side.

These changes re-add type checking for the output side by generating the following TCB instead:

```
someOutput.subscribe($event => {
  var _t1 = unwrapSignalValue(this.someField);
  _t1 = $event;
});
```
Moves the fix for type checking the event side of two-way bindings behind a compiler flag so that we can roll it out in v20.
@crisbeto crisbeto force-pushed the 58971/two-way-binding-checking branch from 713a598 to ba9fbe0 Compare December 5, 2024 17:16
@crisbeto crisbeto added action: review The PR is still awaiting reviews from at least one requested reviewer and removed action: global presubmit The PR is in need of a google3 global presubmit labels Dec 5, 2024
@crisbeto crisbeto marked this pull request as ready for review December 5, 2024 17:30
@pullapprove pullapprove bot requested a review from alxhub December 5, 2024 17:30
const strictTemplates = !!this.options.strictTemplates;

const useInlineTypeConstructors = this.programDriver.supportsInlineOperations;
const checkTwoWayBoundEvents = this.options['_checkTwoWayBoundEvents'] ?? false;
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.

Note that this is off by default so we can land it in g3. I'll flip it to true internally once I fix all the breakages and in v20 externally.

@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 Dec 5, 2024
@alxhub
Copy link
Copy Markdown
Member

alxhub commented Dec 6, 2024

This PR was merged into the repository by commit 6fd8a20.

The changes were merged into the following branches: main

@alxhub alxhub closed this in 68c5e02 Dec 6, 2024
alxhub pushed a commit that referenced this pull request Dec 6, 2024
In the past two-way bindings used to be interpreted as `foo = $event` at the parser level. In #54065 it was changed to preserve the actual expression, because it was problematic for supporting two-way binding to signals. This unintentionally ended up causing the TCB to two-way bindings to look something like `someOutput.subscribe($event => expr);` which does nothing. It largely hasn't been a problem, because the input side of two-way bindings was still being checked, except for the case where the input side of the two-way binding has a wider type than the output side.

These changes re-add type checking for the output side by generating the following TCB instead:

```
someOutput.subscribe($event => {
  var _t1 = unwrapSignalValue(this.someField);
  _t1 = $event;
});
```

PR Close #59002
alxhub pushed a commit that referenced this pull request Dec 6, 2024
Moves the fix for type checking the event side of two-way bindings behind a compiler flag so that we can roll it out in v20.

PR Close #59002
crisbeto added a commit to crisbeto/angular that referenced this pull request Dec 6, 2024
…way bindings

Follow-up to angular#59002. If a two-way binding is non-null asserted, only the property side was getting the assertion since the `$event` is synthetic. In practice this means that there's no way to non-null assert a two-way binding. These changes fix the issue by checking if the handler is asserted and applying it to the `$event` assignment.
crisbeto added a commit to crisbeto/angular that referenced this pull request Dec 10, 2024
…s when narrowed

After angular#59002, we started producing code like the following for the event side of two-way bindings:

```
someOutput.subscribe($event => {
  var _t1 = unwrapSignalValue(this.someField);
  _t1 = $event;
});
```

The problem with this approach is that if `someField` is narrowed, the type of `_t1` will be narrowed as well which will make `$event` unassignable. This came up when trying to roll out the changes from the previous PR internally.

These changes rework the approach by generating a function call instead. Now the TCB looks as follows:

```
someOutput.subscribe($event => {
  assignTwoWayBinding(this.someField, $event);
});
```
@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 Jan 6, 2025
PrajaktaB27 pushed a commit to PrajaktaB27/angular that referenced this pull request Feb 7, 2025
The `isSplitTwoWayBinding` function was a bit misleading, because it has side effects. Renames the function make it a bit more explicit.

PR Close angular#59002
PrajaktaB27 pushed a commit to PrajaktaB27/angular that referenced this pull request Feb 7, 2025
In the past two-way bindings used to be interpreted as `foo = $event` at the parser level. In angular#54065 it was changed to preserve the actual expression, because it was problematic for supporting two-way binding to signals. This unintentionally ended up causing the TCB to two-way bindings to look something like `someOutput.subscribe($event => expr);` which does nothing. It largely hasn't been a problem, because the input side of two-way bindings was still being checked, except for the case where the input side of the two-way binding has a wider type than the output side.

These changes re-add type checking for the output side by generating the following TCB instead:

```
someOutput.subscribe($event => {
  var _t1 = unwrapSignalValue(this.someField);
  _t1 = $event;
});
```

PR Close angular#59002
PrajaktaB27 pushed a commit to PrajaktaB27/angular that referenced this pull request Feb 7, 2025
…#59002)

Moves the fix for type checking the event side of two-way bindings behind a compiler flag so that we can roll it out in v20.

PR Close angular#59002
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 target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants