Angular 14: Typed form with generic type not working

Viewed 151

I want to build a form which can have multiple filters. Each filter consists of a fieldName, operator and a value. The type of the value is related to the fieldName.

This is my filterModel:

export type FilterModel<T> = { [K in keyof T]: {
    fieldName: K | null,
    fieldNameData: DisplayValue<K>[];
    operator: FilterOperator | null,
    operatorData: DisplayValue<FilterOperator>[],
    value: T[K] | null
} }[keyof T]

With which I can achieve the following:

interface User {
    name: string;
    age: number;
}

const userFilter: FilterModel<User> = {
    fieldName: 'age',
    fieldNameData: [],
    operator: FilterOperator.Contains,
    operatorData: [],
    value: 3
}

const userFilter: FilterModel<User> = {
    fieldName: 'age',
    fieldNameData: [],
    operator: FilterOperator.Contains,
    operatorData: [],
    value: '' <-- Error because number is expected for field 'age'
}

Now I want to build a generic filter component, that is passed a FilterModel of any type (FilterModel<T>). This component defines the controls in the template etc. I also created a mapped type so I can use any model in a typed FormGroup:

export type FormGroupModel<T> = {
    [Property in keyof T] : FormControl<T[Property]>;
}

What works:

  public workingForm = new FormGroup<FormGroupModel<FilterModel<User>>>({
    fieldName: new FormControl('name'),
    fieldNameData: new FormControl([], { nonNullable: true }),
    operator: new FormControl(null),
    operatorData: new FormControl([], { nonNullable: true }),
    value: new FormControl(''),
  });

I can use it without a problem in my template (the control attribute is expecting a FormControl):

<dropdown-field [control]="workingForm.controls.fieldName"></dropdown-field>

What doesn't work:

export class FilterComponent<T> implements OnInit {
 @Input() public notWorkingForm! = new FormGroup<FormGroupModel<FilterModel<T>>>(); // this is should be created by parent

But my template has now an error

<dropdown-field [control]="notWorkingForm.controls.fieldName"></dropdown-field>

enter image description here

Somehow, when using a generic type, I am not receiving FormControls, but Abstract Controls. I am not sure what I'm doing wrong. I believe something like this should be possible with the new typed forms in angular 14.

Can someone help? I really would like to have a type safe form here.

EDIT

I noticed that I cannot set the generic Input "form" because I always get "Type is not assignable". Maybe my approach is generally wrong?

0 Answers
Related