From c35587ba568f2eeeddfd230f766d207b8b53e842 Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Sat, 26 Oct 2019 09:46:25 -0400 Subject: [PATCH] docs: add template type-checking guide (#33421) PR Close #33421 --- .github/CODEOWNERS | 1 + aio/content/guide/template-typecheck.md | 119 +++++++++++++++++++++ aio/content/guide/updating-to-version-9.md | 8 +- aio/content/navigation.json | 7 +- 4 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 aio/content/guide/template-typecheck.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 231a7642d3..08e0697bfb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -447,6 +447,7 @@ /aio/content/guide/angular-compiler-options.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes /aio/content/guide/aot-compiler.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes /aio/content/guide/aot-metadata-errors.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/template-typecheck.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes diff --git a/aio/content/guide/template-typecheck.md b/aio/content/guide/template-typecheck.md new file mode 100644 index 0000000000..d13a6034a4 --- /dev/null +++ b/aio/content/guide/template-typecheck.md @@ -0,0 +1,119 @@ +# Template type-checking + +## Overview of template type-checking + +Just as TypeScript catches type errors in your code, Angular checks the expressions and bindings within the templates of your application and can report any type errors it finds. Angular currently has three modes of doing this, depending on the value of the `fullTemplateTypeCheck` and `strictTemplates` flags. + +### Basic mode + +In the most basic type-checking mode, with the `fullTemplateTypeCheck` flag set to `false`, Angular will only validate top-level expressions in a template. + +If you write ``, the compiler will verify the following: + +* `user` is a property on the component class. +* `user` is an object with an address property. +* `user.address` is an object with a city property. + +The compiler will not verify that the value of `user.address.city` is assignable to the city input of the `` component. + +The compiler also has some major limitations in this mode: + +* Importantly, it won't check embedded views, such as `*ngIf`, `*ngFor`, other `` embedded view. +* It won't figure out the types of `#refs`, the results of pipes, the type of `$event` in event bindings, etc. +* In many cases, these things end up as type `any` which can cause subsequent parts of the expression to go unchecked. + + + +### Full mode + +If the `fullTemplateTypeCheck` flag is set to `true`, Angular will be more aggressive in its type-checking within templates. +In particular: + +* Embedded views (such as those within an `*ngIf` or `*ngFor`) will be checked. +* Pipes will have the correct return type. +* Local references to directives and pipes will have the correct type (except for any generic parameters, which will be `any`). +* Local references to DOM elements will still have type `any`. +* `$event` will still have type `any`. +* Safe navigation expressions will still have type `any`. + + +### Strict mode + +Angular version 9 maintains the behavior of the `fullTemplateTypeCheck` flag, and introduces a third "strict mode". +Strict mode is accessed by setting both `fullTemplateTypeCheck` and the `strictTemplates` flag to `true`. +In strict mode, Angular version 9 adds checks that go beyond the version 8 type-checker. +Note that strict mode is only available if using Ivy. + +In addition to the full mode behavior, Angular version 9: + +* Verifies that component/directive bindings are assignable to their `@Input()`s. +* Obeys TypeScript's `strictNullChecks` flag when validating the above. +* Infers the correct type of components/directives, including generics. +* Infers template context types where configured (for example, allowing correct type-checking of `NgFor`). +* Infers the correct type of `$event` in component/directive, DOM, and animation event bindings. +* Infers the correct type of local references to DOM elements, based on the tag name (for example, the type that `document.createElement` would return for that tag). + + +## Checking of `*ngFor` + +The three modes of type-checking treat embedded views differently. Consider the following example: + + + + +interface User { + name: string; + address: { + city: string; + state: string; + } +} + + + + +```html +
+

{{config.title}}

+ City: {{user.address.city}} +
+``` + +The `

` and the `` are in the `*ngFor` embedded view. +In basic mode, Angular doesn't check either of them. +However, in full mode, Angular checks that `config` and `user` exists and assumes a type of `any`. +In strict mode, Angular knows that the `user` in the `` has a type of `User` as well as `address` is an object with a `city` property of type `string`. + + +## Troubleshooting template errors + +When enabling the new strict mode in version 9, you might encounter template errors which didn't arise in either of the previous modes. These errors often represent genuine type mismatches in the templates which were not caught by the previous tooling. If this is the case, the error message should make it clear where in the template the problem occurs. + +They can also be false positives when the typings of an Angular library are either incomplete or incorrect, or when the typings don't quite line up with expectations as in the following: + +1. When a library's typings are wrong or incomplete (for example, missing `null | undefined` if the library was not written with `strictNullChecks` in mind). +1. When a library's input types are too narrow and the library hasn't added appropriate metadata for Angular to figure this out. This usually occurs with disabled or other common boolean inputs used as attributes, for example, ``. +1. When using `$event.target` for DOM events (because of the possibility of event bubbling, `$event.target` in the DOM typings doesn't have the type you might expect). + +It's also possible that an error can be the result of a bug in the template type-checker itself. + +In case of a false positive like these, there are a few options: + +* `$any()` can be used in certain contexts to opt out of type-checking for a part of the expression. +* `strictTemplates` can be disabled entirely. +* Certain type-checking operations can be disabled individually, while maintaining strictness in other aspects, by setting a _strictness flag_ to `false`. + +|Strictness flag|Effect| +|-|-| +|`strictInputTypes`|Whether the assignability of a binding expression to the `@Input()` field is checked. Also affects the inference of directive generic types. | +|`strictNullInputTypes`|Whether `strictNullChecks` is honored when checking `@Input()` bindings (per `strictInputTypes`). Turning this off can be useful when using a library that was not built with `strictNullChecks` in mind.| +|`strictAttributeTypes`|Whether to check `@Input()` bindings that are made using text attributes (for example, `` vs ``). +|`strictSafeNavigationTypes`|Whether the return type of safe navigation operations (for example, `user?.name`) will be correctly inferred based on the type of `user`). If disabled, `user?.name` will be of type `any`. +|`strictDomLocalRefTypes`|Whether local references to DOM elements will have the correct type. If disabled `ref` will be of type `any` for ``.| +|`strictOutputEventTypes`|Whether `$event` will have the correct type for event bindings to component/directive an `@Output()`, or to animation events. If disabled, it will be `any`.| +|`strictDomEventTypes`|Whether `$event` will have the correct type for event bindings to DOM events. If disabled, it will be `any`.| + + +If you still have issues after troubleshooting with these flags, you can fall back to full mode by disabling `strictTemplates`. + +If that doesn't work, an option of last resort is to turn off full mode entirely with `fullTemplateTypeCheck: false`, as we've made a special effort to make Angular version 9 backwards compatible in this case. If you get errors that require falling back to basic mode, then please [file an issue](https://github.com/angular/angular/issues) so the team can address it, as it is almost definitely a bug. diff --git a/aio/content/guide/updating-to-version-9.md b/aio/content/guide/updating-to-version-9.md index 539c690869..81d4e99bf4 100644 --- a/aio/content/guide/updating-to-version-9.md +++ b/aio/content/guide/updating-to-version-9.md @@ -24,7 +24,7 @@ If you're curious about the specific migrations being run (e.g. what code is cha ## Changes and Deprecations in Version 9 {@a breaking-changes} -### New Breaking Changes +### New Breaking Changes - Angular now compiles with Ivy by default. See [Ivy compatibility section](#ivy). @@ -63,6 +63,12 @@ If you're curious about the specific migrations being run (e.g. what code is cha +{@a ivy-features} +## Ivy Features + +Angular version 9 introduces more comprehensive type-checking. For details, see [Template Type-checking](guide/template-typecheck). + + {@a ivy} ## Ivy Compatibility diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 0b66da7a8c..7a17a65f53 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -611,7 +611,12 @@ "url": "guide/aot-metadata-errors", "title": "AoT Metadata Errors", "tooltip": "Troubleshooting AoT compilation." - } + }, + { + "url": "guide/template-typecheck", + "title": "Template Type-checking", + "tooltip": "Template type-checking in Angular." + } ] }, {