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

feat(compiler-cli): Support template binding to protected component members #45823

Closed
wants to merge 1 commit into from

Conversation

zelliott
Copy link
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

(unclear if any docs need to be updated)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Currently, you can not create a template binding to a protected component member. For example:

@Component({
  selector: 'my-component',
  template: '{{message}}',  // Does not compile, as `message` is protected and not visible to the template.
})
export class MyComponent {
  protected message = 'Hello world';
}

Issue Number: N/A

What is the new behavior?

Now, the code above compiles.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@google-cla
Copy link

google-cla bot commented Apr 29, 2022

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

For more information, open the CLA check for this pull request.

@zelliott zelliott force-pushed the protected-bindings branch from 9641f04 to 8f190fe Compare April 29, 2022 22:18
@zelliott
Copy link
Contributor Author

zelliott commented Apr 29, 2022

@JoostK JFYI - I think the test failures on CircleCI are real failures that we don't want. I think the original diagnostic messages are correct. Looking into it, but LMK if you have any thoughts. It looks like we're hitting this scenario: http://typescriptlang.org/docs/handbook/2/classes.html#cross-hierarchy-protected-access.

@zelliott
Copy link
Contributor Author

I think the scenario is essentially this:

// some-cmp.ng.html
// <other-cmp [foo]="bar"></other-cmp>

class SomeCmp {
    bar = 5;
}

class OtherCmp {
    protected foo = 4;
}

function tcb(this: SomeCmp): void {
  var ctx = this;
  var _t1: OtherCmp = null!;
  _t1.foo = ctx.bar;
}

where the expression _t1.foo has the error:

Property 'foo' is protected and only accessible through an instance of class 'SomeCmp'. This is an instance of class 'OtherCmp'.

Here's a TS Playground: https://www.typescriptlang.org/play?#code/PTAEGcHsFsFMFoDG0AOA6AdgczQCwC7QA2AUCKADyT66wBOSqoA2gGaSQC6AvAEQBGAQzq8AfBWDVaDZClEkSiIoPDhQAZRiwAwkwDeJUEdBC6obqACsAbhIBfBUpVqA8jXq6UoA8dAo61LCI+LAAJqDskOagACy2DiSsAK4YwQCWkBig+Ij8ABQ0aeAAXBpangCUpQBukGnhPqDVwqDBAB7RheC2Rs1mAPr4AIylbtKe0RhJREQAhD2gg0NokdHtaKbxQA

Previously, before this PR, the error read:

Property 'foo' is protected and only accessible within class 'OtherCmp' and its subclasses.

Which is I think much clearer. Are these diagnostic messages user-facing? If so, this new error message might be a problem. Otherwise, maybe it's fine to just update the test assertion to expect the new error message.

@JoostK
Copy link
Member

JoostK commented Apr 30, 2022

Those errors are indeed user-facing; we only translate the TS diagnostics to their original template location but we use the messages directly.

Interestingly, this behaviour was changed in microsoft/TypeScript#47991 for TS 4.7 and if you switch the playground over to Nightly you'll find that the error is as it used to be. We've only switched the repo over to TS 4.7 in the last couple days and it is super strange that the test job succeeds, but only test_win fails. I suspect that test_win is somehow still pulling in TS 4.6 as otherwise I have no idea how it can report different diagnostics compared to the Linux test job.

@zelliott
Copy link
Contributor Author

Nice find! What's the best path forward then? It sounds like we need to determine why test_win doesn't seem to be on TS 4.7. Who's the best person to look into this? I'm not sure exactly where to start, might be more efficient for someone more familiar with Angular's testing infra.

@JoostK
Copy link
Member

JoostK commented Apr 30, 2022

I just SSH'd into the Windows box to see what's going on, and the root cause is that the Windows CI job does not use the rebased checkout, unlike the Linux test jobs (the rebase is done in the setup job). You'll have to fetch latest main from angular/angular and rebase on top of it, then force push to also run the Windows tests using TypeScript 4.7. I'll mention this to infra folks.

@zelliott zelliott force-pushed the protected-bindings branch from 8f190fe to 46d8e94 Compare April 30, 2022 20:12
@zelliott
Copy link
Contributor Author

Great, looks like that resolved it.

@zelliott
Copy link
Contributor Author

zelliott commented May 1, 2022

@JoostK, regarding this:

I'm sending a quick addendum to my previous suggestion as I realized we also emit nested function expressions into a type-check function, which would have a separate this pointer. This means that the proposed change won't work, but this can be worked around by generating a single const ctx = this; as first statement into the type-check function such that references can continue to use ctx as they do today.

I haven't been able to get this addendum to work. Here's a playground that demonstrates. Am I missing something?

Note that we can still use string index notation to work around this (and also bind to private members), but I know you have concerns around the stability of that TS behavior.

EDIT: Maybe we can do something like this: Another playground. Not sure if this breaks other stuff.

@JoostK
Copy link
Member

JoostK commented May 1, 2022

The idea of the const ctx = this; alias was to be able to use ctx within a function expression instead of this directly, as the function expression would have its own calling context. Your playgrounds show that using ctx from within such function expression voids the privileged access to protected members, so we need some other way.

I see two possibilities, one of which actually seems to work:

  1. Change the function expression into an arrow function. Playground.
  2. Add an explicit this: TestComponent parameter to function expressions. Playground. This doesn't actually work because addEventListener doesn't accept a listener with bound this type, so this approach is not feasible it seems.

We can get rid of the const ctx = this; alias in both cases, as all usages can then be updated to use this directly.

@zelliott zelliott force-pushed the protected-bindings branch from 5d0272e to 2d30eec Compare May 2, 2022 15:50
@zelliott
Copy link
Contributor Author

zelliott commented May 2, 2022

Yep, makes sense. Changed to an arrow function, removed the const ctx = this, and updated tests accordingly.

@zelliott zelliott marked this pull request as ready for review May 2, 2022 17:17
@pullapprove pullapprove bot requested a review from atscott May 2, 2022 17:18
@zelliott
Copy link
Contributor Author

zelliott commented May 2, 2022

  • g3sync: cl/445520050 (the g3sync command pulled in some changes from other commits, not sure if this is expected, but I reverted them before running TGP).
  • Testing this PR with some real-world g3 code: cl/445417620 (LGTM).

@dylhunn dylhunn added the area: compiler Issues related to `ngc`, Angular's template compiler label May 2, 2022
@ngbot ngbot bot added this to the Backlog milestone May 2, 2022
@@ -585,6 +585,29 @@ class TestComponent {
expect(messages).toEqual(
[`TestComponent.html(3, 30): Type 'HTMLElement' is not assignable to type 'string'.`]);
});

it('allows access to protected members', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Should there be similar tests for @Directive as well?

Copy link
Member

Choose a reason for hiding this comment

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

I don't believe there's any template type-checking associated with directives.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alxhub This thread made me think of host attribute bindings and whether it was possible today to create a host attribute binding to a protected/private member. From my testing on StackBlitz, it looks like it's already possible (which surprised me).

Copy link
Member

Choose a reason for hiding this comment

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

We don't type-check host bindings at all at the moment (not since Ivy, at least; VE had limited type-checking of host bindings)

Copy link
Member

Choose a reason for hiding this comment

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

Well, that sounds like something for the backlog

alxhub
alxhub previously approved these changes May 2, 2022
@alxhub alxhub added the target: minor This PR is targeted for the next minor release label May 2, 2022
@alxhub alxhub modified the milestones: Backlog, v14-candidates May 2, 2022
JoostK
JoostK previously approved these changes May 2, 2022
Copy link
Member

@JoostK JoostK left a comment

Choose a reason for hiding this comment

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

Great work! It would be great if you could also update the README.md file to reflect the changes.

@zelliott zelliott dismissed stale reviews from JoostK and alxhub via 33e4d29 May 2, 2022 18:58
@zelliott zelliott force-pushed the protected-bindings branch from 2d30eec to 33e4d29 Compare May 2, 2022 18:58
@zelliott zelliott requested a review from JoostK May 2, 2022 19:00
JoostK
JoostK previously approved these changes May 2, 2022
…embers

This commit adds support for creating template bindings to protected members within the component class.
@zelliott
Copy link
Contributor Author

zelliott commented May 2, 2022

I realized I think I'm "dismissing" these reviews with my force pushes (rebasing + force pushing to avoid a ton of noisy commits). Please LMK if this isn't the right workflow for future reference!

@zelliott
Copy link
Contributor Author

zelliott commented May 2, 2022

  • g3sync: cl/445520050 (the g3sync command pulled in some changes from other commits, not sure if this is expected, but I reverted them before running TGP).
  • Testing this PR with some real-world g3 code: cl/445417620 (LGTM).

g3sync PR looks good except for some already failing targets.

@zelliott zelliott requested review from alxhub and JoostK May 2, 2022 19:53
@JoostK JoostK added the action: merge The PR is ready for merge by the caretaker label May 2, 2022
@jelbourn
Copy link
Member

jelbourn commented May 2, 2022

@zelliott we just turned on a new branch protection feature that dismisses all approvals when new commits are pushed as a security safeguard. For the time being, this prevents the "lgtm with nits" workflow until we add some additional tooling.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

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

lgtm

@atscott
Copy link
Contributor

atscott commented May 2, 2022

presubmit

@dylhunn
Copy link
Contributor

dylhunn commented May 2, 2022

This PR was merged into the repository by commit 752ddbc.

@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 Jun 2, 2022
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 hotlist: google target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants