feat(ivy): strictness flags for template type checking (#33365)
The template type checking abilities of the Ivy compiler are far more advanced than the level of template type checking that was previously done for Angular templates. Up until now, a single compiler option called "fullTemplateTypeCheck" was available to configure the level of template type checking. However, now that more advanced type checking is being done, new errors may surface that were previously not reported, in which case it may not be feasible to fix all new errors at once. Having only a single option to disable a large number of template type checking capabilities does not allow for incrementally addressing newly reported types of errors. As a solution, this commit introduces some new compiler options to be able to enable/disable certain kinds of template type checks on a fine-grained basis. PR Close #33365
This commit is contained in:
@ -425,26 +425,29 @@ export class NgtscProgram implements api.Program {
|
||||
// requested.
|
||||
let typeCheckingConfig: TypeCheckingConfig;
|
||||
if (this.options.fullTemplateTypeCheck) {
|
||||
const strictTemplates = !!this.options.strictTemplates;
|
||||
typeCheckingConfig = {
|
||||
applyTemplateContextGuards: true,
|
||||
checkQueries: false,
|
||||
checkTemplateBodies: true,
|
||||
checkTypeOfInputBindings: true,
|
||||
strictNullInputBindings: true,
|
||||
checkTypeOfAttributes: true,
|
||||
checkTypeOfInputBindings: strictTemplates,
|
||||
strictNullInputBindings: strictTemplates,
|
||||
checkTypeOfAttributes: strictTemplates,
|
||||
// Even in full template type-checking mode, DOM binding checks are not quite ready yet.
|
||||
checkTypeOfDomBindings: false,
|
||||
checkTypeOfOutputEvents: true,
|
||||
checkTypeOfAnimationEvents: true,
|
||||
checkTypeOfOutputEvents: strictTemplates,
|
||||
checkTypeOfAnimationEvents: strictTemplates,
|
||||
// Checking of DOM events currently has an adverse effect on developer experience,
|
||||
// e.g. for `<input (blur)="update($event.target.value)">` enabling this check results in:
|
||||
// - error TS2531: Object is possibly 'null'.
|
||||
// - error TS2339: Property 'value' does not exist on type 'EventTarget'.
|
||||
checkTypeOfDomEvents: false,
|
||||
checkTypeOfDomReferences: true,
|
||||
checkTypeOfDomEvents: strictTemplates,
|
||||
checkTypeOfDomReferences: strictTemplates,
|
||||
// Non-DOM references have the correct type in View Engine so there is no strictness flag.
|
||||
checkTypeOfNonDomReferences: true,
|
||||
// Pipes are checked in View Engine so there is no strictness flag.
|
||||
checkTypeOfPipes: true,
|
||||
strictSafeNavigationTypes: true,
|
||||
strictSafeNavigationTypes: strictTemplates,
|
||||
};
|
||||
} else {
|
||||
typeCheckingConfig = {
|
||||
@ -465,6 +468,31 @@ export class NgtscProgram implements api.Program {
|
||||
};
|
||||
}
|
||||
|
||||
// Apply explicitly configured strictness flags on top of the default configuration
|
||||
// based on "fullTemplateTypeCheck".
|
||||
if (this.options.strictInputTypes !== undefined) {
|
||||
typeCheckingConfig.checkTypeOfInputBindings = this.options.strictInputTypes;
|
||||
}
|
||||
if (this.options.strictNullInputTypes !== undefined) {
|
||||
typeCheckingConfig.strictNullInputBindings = this.options.strictNullInputTypes;
|
||||
}
|
||||
if (this.options.strictOutputEventTypes !== undefined) {
|
||||
typeCheckingConfig.checkTypeOfOutputEvents = this.options.strictOutputEventTypes;
|
||||
typeCheckingConfig.checkTypeOfAnimationEvents = this.options.strictOutputEventTypes;
|
||||
}
|
||||
if (this.options.strictDomEventTypes !== undefined) {
|
||||
typeCheckingConfig.checkTypeOfDomEvents = this.options.strictDomEventTypes;
|
||||
}
|
||||
if (this.options.strictSafeNavigationTypes !== undefined) {
|
||||
typeCheckingConfig.strictSafeNavigationTypes = this.options.strictSafeNavigationTypes;
|
||||
}
|
||||
if (this.options.strictDomLocalRefTypes !== undefined) {
|
||||
typeCheckingConfig.checkTypeOfDomReferences = this.options.strictDomLocalRefTypes;
|
||||
}
|
||||
if (this.options.strictAttributeTypes !== undefined) {
|
||||
typeCheckingConfig.checkTypeOfAttributes = this.options.strictAttributeTypes;
|
||||
}
|
||||
|
||||
// Execute the typeCheck phase of each decorator in the program.
|
||||
const prepSpan = this.perfRecorder.start('typeCheckPrep');
|
||||
const ctx = new TypeCheckContext(typeCheckingConfig, this.refEmitter !, this.typeCheckFilePath);
|
||||
|
@ -107,10 +107,10 @@ export interface TypeCheckingConfig {
|
||||
* Whether to check text attributes that happen to be consumed by a directive or component.
|
||||
*
|
||||
* For example, in a template containing `<input matInput disabled>` the `disabled` attribute ends
|
||||
* up being consumed as an input with type `boolean` by the `matInput` directive. At runtime the
|
||||
* input will be set to the attribute's string value, which is the empty string for attributes
|
||||
* without a value, so with this flag set to `true` an error would be reported. If set to `false`,
|
||||
* text attributes will never report an error.
|
||||
* up being consumed as an input with type `boolean` by the `matInput` directive. At runtime, the
|
||||
* input will be set to the attribute's string value, which is an empty string for attributes
|
||||
* without a value, so with this flag set to `true`, an error would be reported. If set to
|
||||
* `false`, text attributes will never report an error.
|
||||
*
|
||||
* Note that if `checkTypeOfInputBindings` is set to `false`, this flag has no effect.
|
||||
*/
|
||||
@ -129,7 +129,8 @@ export interface TypeCheckingConfig {
|
||||
checkTypeOfDomBindings: boolean;
|
||||
|
||||
/**
|
||||
* Whether to infer the type of the `$event` variable in event bindings for directive outputs.
|
||||
* Whether to infer the type of the `$event` variable in event bindings for directive outputs or
|
||||
* animation events.
|
||||
*
|
||||
* If this is `true`, the type of `$event` will be inferred based on the generic type of
|
||||
* `EventEmitter`/`Subject` of the output. If set to `false`, the `$event` variable will be of
|
||||
|
Reference in New Issue
Block a user