In this article, we learn about how to convert the reactive form into strongly-typed without changing the class definition.

Many of us love TypeScript as its Strongly-Typed. This gives the main power to the Angular Framework, But Angular Reactive Forms are not fully Strongly-Typed, Because of the substantial use of ‘any’ keyword, this creates a nasty code while developing the form in terms of mismatch typecasting, typo mistake, etc.

Recently my friend was discussing Strongly-Typed Angular Reactive form challenges. I was thinking on the same note and come up with an intuitive solution by following the Interface Segregation Principle Practices.

Before deep dive into the How part let’s take a glimpse of current challenges :).

Research & Challenges

As the nature of any large scale front end enterprise application, it grows gradually and the forms are an inevitable part of the application. By considering this fact he has done a good amount of customization for making Strongly-Typed Forms to control the typo mistakes and typecasting related issues must arise during build time instead of runtime.  Here are the high-level challenges:

  1. No, build time error if there is a typo mistake in the control name.
  2. Typecasting issue in valueChanges and statusChanges of the FormControl.
  3. Difficult to manage nested FormGroup and FormArray due to lake of typecasting.

All the above problems have been covered with his customization approach by creating generic classes and extending with the base classes(FormGroup, FormControl, and FormArray).  But the challenge still remains in a different manner:

  1. Losing the actual benefit of FormBuilder class for creating FormControl, FormGroup, and FormArray elegantly.
  2. Any single mistake in the generic class will give unexpected behavior throughout the application.
  3. Fair chances of mixing two approaches in the application like some of the FormGroup Object are creating through Generic Classes and some of them are through the base class of @angular/forms.

Let’s dive into the solution which solves all the above-mentioned challenges without increasing the bundle size(0 Byte) of the application.

Without Generic Class, How it’s possible?

As I said in the beginning that with the help of Interface Segregation Principle practices we can achieve End-to-End Strongly-Typed Reactive Form without creating a generic class.

How?

We have to use @rxweb/types for converting our Reactive Form into Strongly-Typed. This package contains only type definitions so there is no risk of code breaks during runtime.
Let’s take a common case which includes FormControl, Nested FormGroup, and Nested FormArray. Here is the code of creating FormGroup.

export class AppComponent implements OnInit {
    formGroup: FormGroup;
    formBuilder: FormBuilder;

    constructor(formBuilder: FormBuilder) {
        this.formBuilder = formBuilder;
    }

    ngOnInit() {
        this.formGroup = this.formBuilder.group({
            firstName: ['', [Validators.required]],
            address: this.formBuilder.group({
                countryName: ["", Validators.required]
            }),
            skills: this.formBuilder.array([
                this.formBuilder.group({
                    name: ["", Validators.required]
                })
            ])
        });
    }
}

Now we are going to convert the above form into strongly-typed by following the four simple steps.

Step 1: Installing the Package

npm install @rxweb/types

Step 2: Creating Interface

All the above-mentioned Control Names would be defined as property in the respective Interface alike User >> firstName, address, skills; Address >> countryName; Skill >> name .

Step 3: Import Generic Interface

We have to import two interfaces which are mentioned below:

  1. IFormGroup: This provides the FormGroup APIs that are Strongly-Typed.
  2. IFormBuilder: This gives an opportunity to create the FormGroup, FormControl, and FormArray to be Strongly-Typed.

Here is the code:

import { IFormGroup, IFormBuilder } from “@rxweb/types”;

Step 4: Convert into Strongly-Typed Reactive Form

For the conversion, we have to follow three simple steps.

  1. Replace FormGroup Type to IFormGroup
  2. Replace FormBuilder Type to IFormBuilder.
  3. Pass Interface to the respective method of group<User>, group<Address>, and array<Skill>.

That’s it 🙂.

Here is the converted Code.

formGroup: IFormGroup<User>;
formBuilder: IFormBuilder; 
	
ngOnInit() {
        
this.formGroup = this.formBuilder.group<User>({
   firstName: ['', [Validators.required]],
   address: this.formBuilder.group<Address>({
       countryName: ["", Validators.required]
        }),
   skills: this.formBuilder.array<Skill>([
        this.formBuilder.group({
           name: ["", Validators.required]
           })
        ])
   });
}

All the mentioned challenges are solved by following the above simple steps.
Here is a quick snap of typecasting/typo mistakes after converting the strongly-typed form.

Typo Mistake

Mismatch Type

You can refer the example which gives you more insights into strongly-typed Reactive Form APIs or else you can refer the documentation for more information.

Conclusion

The fantabulous part is our form to be Strongly-Typed through Interface without change the class definition, but if you are looking for a more than the strongly-typed solution that overcomes the problem of code duplication and following the practices of Single Responsibility Principle,  Domain-Driven Design Practices, so I would suggest Please refer to this article “New Way to Validate the Angular Reactive Form”.

I hope you like this article. If you have any suggestions, please write your comment below.