Issue
While being on the latest version of Angular (version 14), it seems that I am not doing something well and thus strictly typed reactive forms are not working as expected.
Form is initialized inside ngOnInit using injected FormBuilder.
public form!: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit(): void {
this.initializeForm();
}
private initializeForm(): void {
this.form = this.formBuilder.group({
title: ['', [Validators.required, Validators.minLength(3)]],
content: ['', Validators.required],
});
}
Now when I try to access controls of the form there is no autocomplete and type is FormGroup<any>. Also it doesn't throw the error when trying to access controls which are not present on the FormGroup object.
- Example:
package.json
- Angular official documentation:
https://angular.io/guide/typed-forms
Solution
TL;DR: The way TypeScript identifies its "types" mostly due to interfaces and context. To solve use an explicit interface and pass it to the form as it cannot be inferred.
You can check how type inference works for more detail in typescriptlang, here´s a small extract:
Simple type let x = 4 being number
The type of the x variable is inferred to be number. The kind of inference takes place when initializing variables and members, setting parameter default values, and determining function return types.
Best common type let x = [0, 1, null] being of type (number | null)[]
To infer the type of x in the example above, we must consider the type of each array element. Here we are given two choices for the type of the array: number and null. The best common type algorithm considers each candidate type, and picks the type that is compatible with all the other candidates.
Contextual types window.onmousedown = function (mouseEvent) { ... }, being MouseEvent
Contextual typing applies in many cases. Common cases include arguments to function calls, right hand sides of assignments, type assertions, members of object and array literals, and return statements. The contextual type also acts as a candidate type in best common type.
Your use case:
There's no way way to infer the form type, you've to explicitly tell. I've made this working example of a typed form. The official documentation you included in your question kind of already gives you most of the answer.
To remove the <any> you see in your autocomplete, just implement your own interface:
export interface IMainForm {
title: FormControl<string>;
content: FormControl<string>;
}
public form!: FormGroup<IMainForm>; // <--- Use your interface
Also, your implementation of this.formBuilder.group is deprecated because is not typesafe. You'll need to use the overload with AbstractControlOptions instead (not the array one).
private initializeForm(): void {
this.form = this.formBuilder.group({
title: new FormControl<string|null>(null, [Validators.required, Validators.minLength(3)]),
content: new FormControl<string|null>(null, Validators.required)
});
}
As you can see in the following image, with those changes you'll see the typed value {Partial<{ title: string; content: string; }>}.

Answered By - luiscla27


0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.