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

The structural directive type check docs section is incomplete #40739

Closed
ArielGueta opened this issue Feb 6, 2021 · 12 comments
Closed

The structural directive type check docs section is incomplete #40739

ArielGueta opened this issue Feb 6, 2021 · 12 comments
Labels
help wanted An issue that is suitable for a community contributor (based on its complexity/scope). P4 A relatively minor issue that is not relevant to core functions
Milestone

Comments

@ArielGueta
Copy link

The following docs section is incomplete:

https://angular.io/guide/structural-directives#directive-type-checks

export type Loaded = { type: 'loaded', data: T };
export type Loading = { type: 'loading' };
export type LoadingState = Loaded | Loading;
export class IfLoadedDirective {
    @Input('ifLoaded') set state(state: LoadingState) {}
    static ngTemplateGuard_state(dir: IfLoadedDirective, expr: LoadingState): expr is Loaded { return true; };
}

export interface Person {
  name: string;
}

@Component({
  template: `<div *ifLoaded="state">{{ state.data }}</div>`,
})
export class AppComponent {
  state: LoadingState;
}

The type guard allows the type checker to infer that the acceptable type of state within the template is a Loaded, and further infer that T must be an instance of Person.

  • Where is T comes from?
  • How do we use the Person interface?
  • The directive decorator is missing.
@JoostK
Copy link
Member

JoostK commented Feb 6, 2021

The fact that T and the usage of Person is missing appears to be a rendering issue; it is authored as expected in the source:

export type Loaded<T> = { type: 'loaded', data: T };
export type Loading = { type: 'loading' };
export type LoadingState<T> = Loaded<T> | Loading;
export class IfLoadedDirective<T> {
@Input('ifLoaded') set state(state: LoadingState<T>) {}
static ngTemplateGuard_state<T>(dir: IfLoadedDirective<T>, expr: LoadingState<T>): expr is Loaded<T> { return true; };
}
export interface Person {
name: string;
}
@Component({
template: `&lt;div *ifLoaded="state">{{ state.data }}&lt;/div>`,
})
export class AppComponent {
state: LoadingState<Person>;
}

I suspect that the angle brackets need to be converted into html entities.

@ngbot ngbot bot added this to the needsTriage milestone Feb 6, 2021
@gkalpak
Copy link
Member

gkalpak commented Feb 6, 2021

Yes, the brackets need to be HTML-escaped.

Yet another case where hard-coded code snippets don't serve us well 😛
Ideally we should convert these to doc-regions.

@petebacondarwin
Copy link
Member

👍 to doc regions. Of course if the code was in backticks then the code would be escaped but not in code-example tags.

@ArielGueta
Copy link
Author

Thanks. I don't know if it's the right place, but it doesn't seems to work. I copied the code from the example and this is result:

Screen Shot 2021-02-07 at 7 25 19

The fullTemplateTypeCheck is set to true, and I'm using Ivy.

@JoostK
Copy link
Member

JoostK commented Feb 7, 2021

You'll want to usestrictTemplates set to true instead of fullTemplateTypeCheck.

@iftee-hussain
Copy link
Contributor

If anyone is already not working on it, I can give it a try to create a PR converting these to doc-regions

@iftee-hussain
Copy link
Contributor

iftee-hussain commented Feb 7, 2021

This is not working https://stackblitz.com/edit/angular-bwvsh3
Am I missing something?

@JoostK
Copy link
Member

JoostK commented Feb 8, 2021

This is not working https://stackblitz.com/edit/angular-bwvsh3
Am I missing something?

The example in the docs is only concerning the type-check capabilities of the directive, its actual runtime implementation of rendering its template when in the loaded state is not included (so in your StackBlitz nothing actually happens). Also note that the ngTemplateContextGuard function is never executed at runtime: its sole purpose is to provide a TypeScript signature to model the type narrowing behavior of the directive; this explains why the console.log inside that static method is not logged in StackBlitz.

@ArielGueta
Copy link
Author

@JoostK switched to strictTemplates and still the same:

image

@jelbourn jelbourn added help wanted An issue that is suitable for a community contributor (based on its complexity/scope). P4 A relatively minor issue that is not relevant to core functions labels Feb 10, 2021
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Feb 10, 2021
@mariusgau
Copy link

This is not working https://stackblitz.com/edit/angular-bwvsh3
Am I missing something?

The example in the docs is only concerning the type-check capabilities of the directive, its actual runtime implementation of rendering its template when in the loaded state is not included (so in your StackBlitz nothing actually happens). Also note that the ngTemplateContextGuard function is never executed at runtime: its sole purpose is to provide a TypeScript signature to model the type narrowing behavior of the directive; this explains why the console.log inside that static method is not logged in StackBlitz.

I want to help and create a PR. @JoostK the documentation (https://angular.io/guide/structural-directives#directive-type-checks) says

The IfLoadedDirective definition declares the static field ngTemplateGuard_state, which expresses the narrowing behavior. Within the AppComponent template, the *ifLoaded structural directive should render this template only when state is actually Loaded|Person|.

So I don't understand why ist <div *ifLoaded="loading">Loading...</div> rendered in @iftee-hussain example when loading: Loading (https://stackblitz.com/edit/angular-bwvsh3)

@DMezhenskyi
Copy link
Contributor

Thanks. I don't know if it's the right place, but it doesn't seems to work. I copied the code from the example and this is result:

Screen Shot 2021-02-07 at 7 25 19

The fullTemplateTypeCheck is set to true, and I'm using Ivy.

Hi @ArielGueta!
Did you try to change static ngTemplateGuard_state to static ngTemplateGuard_ifLoaded?

markostanimirovic added a commit to markostanimirovic/angular that referenced this issue Jun 18, 2022
This commit adds a full example for the IfLoadedDirective and moves
the code to the StackBlitz playground for structural directives.

Fixes angular#40739, angular#37119
markostanimirovic added a commit to markostanimirovic/angular that referenced this issue Jun 18, 2022
This commit adds a full example for the IfLoadedDirective and moves
the code to the StackBlitz playground for structural directives.

Fixes angular#40739, angular#37119
AndrewKushnir pushed a commit that referenced this issue Jun 21, 2022
This commit adds a full example for the IfLoadedDirective and moves
the code to the StackBlitz playground for structural directives.

Fixes #40739, #37119

PR Close #46425
@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 Jul 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted An issue that is suitable for a community contributor (based on its complexity/scope). P4 A relatively minor issue that is not relevant to core functions
Projects
None yet
Development

No branches or pull requests

8 participants