Angular strongly typed reactive forms
The most elegant solution is leveraging TypeScript declaration files (*.d.ts
) to introduce generic interfaces extending the standard form classes like AbstractControl
, FormControl
, etc. It doesn’t introduce any new functionality and has no footprint in the compiled JavaScript, but at the same time enforcing strong type checking.
It was suggested by Daniele Morosinotto in March this year and there are talks now to include it in Angular 9.
Adopting the solution is straightforward:
- Download
TypedForms.d.ts
from this gist and save it assrc/typings.d.ts
in your project (Angular 6+ already knows how to use this file). - Start using the new types (
FormGroupTyped<T>
,FormControlTyped<T>
, etc.) whenever you need a strong type validation (see examples in that gist or stackblitz).
For more information, check out a blog post analysing available solutions for strongly typed forms.
I had a similar issue and this was my solution. I really only cared about the type of the 'value' of the form not the form itself. It ended up looking something like this.
export interface UserFormValue {
first_name: string
last_name: string
referral: string
email: string
password: string
}
...
ngOnInit() {
this.userForm = this.fb.group({
first_name: [ '', Validators.required ],
last_name: [ '', Validators.required ],
referral: [ '' ],
email: [ '', [ Validators.required, Validators.email ] ],
password: [ '', [ Validators.required, Validators.minLength(8) ] ],
});
}
...
Then in the template submit the value
<form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value)">
...
</form>
Now you can add a type to the submit function
onSubmit(userForm: UserFormValue) {
...
}
It's not perfect but has been good enough for my use cases. I really wish there was like this.
userForm: FormGroup<UserFormValue>
For ones who want another solution. I found this article talking about strong type for angular form. Below is my sumary.
interface Person {
name: string;
email: string
}
// Controls in a form group that would emit a Person as it's value
type PersonControls = { [key in keyof Person]: AbstractControl };
type PersonFormGroup = FormGroup & { value: Person, controls: PersonControls };
export class MyFormComponent {
form = new FormGroup({
name: new FormControl(),
email: new FormControl()
} as PersonControls) as PersonFormGroup;
init() {
const name = this.form.controls.name; // strong typed!
}
}