I’m facing an interesting discrepancy between passing AbstractControlOptions
to FormGroup
vs FormArray
.
I have my own classes for my form control objects and I have a custom type in order to keep the everything strongly typed.
type StageControlType = {
stageVolume: FormControl<number>;
actions: FormArray<ActionControl>;
};
export class StageControl extends FormGroup<StageControlType> {
constructor() {
super({
stageVolume: new FormControl(DEFAULT_STAGE_VALUES.stageVolume),
actions: new FormArray<ActionControl>(
[].actions.map(() => new ActionControl()),
),
});
}
}
This gives me an expected error:
error TS2322: Type 'FormControl<number | null>' is not assignable to type 'FormControl<number>'.
Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'.
stageVolume: new FormControl(DEFAULT_STAGE_VALUES.stageVolume),
To fix this, I add the non-nullable option to the stageVolume
attribute:
stageVolume: new FormControl(DEFAULT_STAGE_VALUES.stageVolume{
nonNullable: true, ????
})
This fixes the error. At this point, I wonder why I’m getting the error with my FormGroup
property but not my FormArray
property. So just to be safe, I add non-nullable to my FormArray
property too:
actions: new FormArray<ActionControl>(
DEFAULT_STAGE_VALUES.actions.map(() => new ActionControl()),
{nonNullable: true}, ????
),
And that change gives me this error
error TS2353: Object literal may only specify known properties,
and 'nonNullable' does not exist in type
'AbstractControlOptions | ValidatorFn | ValidatorFn[]'.
{nonNullable: true},
~~~~~~~~~~~
That error does not make any sense to me, because FormGroup
and FormArray
both extend AbstractControl
and accept AbstractControlOptions
as their second parameter. I would expect them to behave the exact same way.
So I try forcing the type of the AbstractControlOptions
:
actions: new FormArray<ActionControl>(
DEFAULT_STAGE_VALUES.actions.map(() => new ActionControl()),
{nonNullable: true} as AbstractControlOptions, ????
),
As I guessed, that fixed the issue. For some reason it wasn’t interpreting the type correctly.
So I thought perhaps I would find out what happens if I add that type force to FormGroup
:
actions: new FormArray<ActionControl>(
DEFAULT_STAGE_VALUES.actions.map(() => new ActionControl()),
{nonNullable: true} as AbstractControlOptions, ????
),
Surprisingly, that yields this error:
error TS2322: Type 'FormControl<number | null>' is not assignable to type 'FormControl<number>'.
Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'.
stageVolume: new FormControl(
~~~~~~~~~~~
So my question is: why do the FormArray
options require an as AbstractControlOptions
to work, while the same type assertion in FormGroup
breaks it?