angular

How can we infer a generic type through an interface onto a FormGroup?


I'm working on a reusable FormArray component and am trying to make better use of Typescript's generics features to minimize my code. I created an interface for FormArrays that iterate FormControls by doing this

export interface FormArrayControlGroup<T>{

    list : FormArray< FormControl< T | null >;

}

Then I apply it to a prop like this

export interface SomeFormGroup{

    someProp : FormGroup< FormArrayControlGroup< myCustomType > >;

}

This works wonderfully so I went to create one for FormArrays that iterate FormGroups by doing this

export interface FormArrayGROUPgroup< T >{

    list : FormArray< FormGroup< T > >;

}

However that causes the following error

Type 'T' does not satisfy the constraint '{ [K in keyof T]: AbstractControl<any, any>; }

Plus if I'm not mistaking FormGroup is already of type <T> which is what allows us to infer our types into it. What do I need to do to get it to work the way I'm trying to use it? I'm forcing myself to dig more into generics in typescript because I've just never been able to identify a need to go that deep into it, so I have no clue what to even search for.


Solution

  • The official FormGroup declaration requires specific generic type:

    export declare class FormGroup<TControl extends {
        [K in keyof TControl]: AbstractControl<any>;
    } = any>
    

    Watch out with TControl generic parameter must be an object where each key is associated with an AbstractControl.

    If we pass a generic type T without ensuring it follows this structure, will infer it as =any.

    Example: stackblitz example or demo repo github

    So to resolve your case would be in my demo I use items instead of list:

    export interface FormArrayGROUPgroup<T extends { [K in keyof T]: AbstractControl<any, any> }> {
      list: FormArray<FormGroup<T>>;
    }