angularangular-reactive-formsformbuilderangular14

FormBuilder with strongly typed form in ng14


I have the following form:

const enum Fields {
  FirstName = 'firstName',
  LastName = 'lastName'
}

interface FormType {
  [Fields.FirstName]: FormControl<string | null>;
  [Fields.LastName]: FormControl<string | null>;
}

public form!: FormGroup<FormType>;

this.form = new FormGroup({
  [Fields.FirstName]: new FormControl(null, { validators: Validators.required }),
  [Fields.LastName]: new FormControl(null, { validators: Validators.required }),
});

The usage of the enum is an habit I took to avoid mistyping.

When I do this.form.getRawValue().firstName, the type of firstName is correctly defined as string | null. However, I prefer to use the FormBuilder to build my forms but I can't find a way to translate the form above using FormBuilder. I tried this:

this.form = this._fb.group<FormType>({
  [Fields.FirstName]: ['', Validators.required],
  [Fields.LastName]: ['', Validators.required],
});

I could of course use a simple FormGroup without any type but it would defeat the purpose :p

However, this does not even work as the inferred type of string | Validators. I tried different things without success.

Is it possible to use the FormBuilder with the strongly typed forms?


Solution

  • For Formbuilder you can provide a raw value, a control, or a boxed value, and the type will be inferred automatically.

    this.form = this._fb.group({
      [Fields.FirstName]: ['', Validators.required],
      [Fields.LastName]: ['', Validators.required],
    });
    

    Update

    We cannot pass type of the model, As FormType expect group with formControl we need to specify formControl to each control.

    this.form = this.fb.group<FormType>({
      [Fields.FirstName]: this.fb.control('', Validators.required),
      [Fields.LastName]:  this.fb.control('', Validators.required),
    });
    
    
    this.form.value //value: Partial<{firstName: string | null;lastName: string | null;}>