mtpultz
mtpultz

Reputation: 18298

Type Mapping Issue When Creating a Typed Reactive Form

Setting up a typed FormGroup mapper in Angular to save a bit of redundant typing when creating a typed FormGroup as we migrate to using typed forms, and it seemed to work until I added a boolean to a form model.

export type FormGroupMap<T> = {
  [key in keyof T]: FormControl<T[keyof T]>;
};

It shows this error once you add isActive the models, but works when properties are all strings. I don't understand what's happening with the types if anyone can point it out?

Error in src/app/app.component.ts (30:5) Type 'FormGroup<{ firstName: FormControl; lastName: FormControl; isActive: FormControl; }>' is not assignable to type 'ExampleFormGroup'. Type 'FormControl<string | boolean>' is not assignable to type 'FormControl'. Type 'string | boolean' is not assignable to type 'string'. Type 'boolean' is not assignable to type 'string'.

Example code with a StackBlitz:

import { Component } from '@angular/core';
import { FormGroup, FormControl, NonNullableFormBuilder } from '@angular/forms';

export interface ExampleModel {
  firstName: string;
  lastName: string;
  isActive: boolean;
}

export type FormGroupMap<T> = {
  [key in keyof T]: FormControl<T[keyof T]>;
};

export type ExampleFormGroup = FormGroup<FormGroupMap<ExampleModel>>;

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  standalone: true,
})
export class AppComponent {
  public form: ExampleFormGroup;

  public constructor(private fb: NonNullableFormBuilder) {
    this.form = this.createFormInstance();
  }

  private createFormInstance(): ExampleFormGroup {
    return this.fb.group({
      firstName: ['', []],
      lastName: ['', []],
      isActive: [false, []],
    });
  }
}

Upvotes: 0

Views: 576

Answers (2)

Jeff Barnes
Jeff Barnes

Reputation: 399

I think you want you mapped type to look something like this:

export type FormGroupMap<T> = FormGroup<{
  [key in keyof T]: FormControl<T[key] | undefined | null>;
}>

Upvotes: 0

mtpultz
mtpultz

Reputation: 18298

I decided to avoid using a type mapping until we see what the Angular team does in order to help with the types. I might use ngx-mf, but for now explicitly defining the type works.

export type ExampleFormGroup = FormGroup<{
  firstName: FormControl<string>;
  lastName: FormControl<string>;
  isActive: FormControl<boolean>;
}>;

Upvotes: 0

Related Questions