KostyaTretyak/ng-stack

FormGroup incorrectly extends Angular's FormGroup

tobiaskraus opened this issue · 2 comments

How to reproduce:

import { FormControl, FormGroup } from '@ng-stack/forms';

interface ValidationModel {
    wrongPassword?: {returnedValue: boolean};
    wrongEmail?: {returnedValue: boolean};
}
const form = new FormGroup<any> ({
    control: new FormControl<any, ValidationModel>('some value')
});
// error:
// Type 'FormGroup<any, ValidatorsModel> | FormControl<any, ValidatorsModel> | 
// FormArray<any, ValidatorsModel>' is not assignable to type 'AbstractControl'.

This error happens, as FormGroup from @ng-stack/forms extends FormGroup of @angular/forms

On the other hand, this works (as FormControl is used directly from @ng-stack/forms):

import { FormControl } from '@ng-stack/forms';

const control = new FormControl<any, ValidationModel>('some value');

errors in form-group.d.ts:

5: Type 'FormGroup<any, ValidatorsModel> | FormControl<any, ValidatorsModel> | FormArray<any, ValidatorsModel>' is not assignable to type 'AbstractControl'.

39: Property 'registerControl' in type 'FormGroup<T, E>' is not assignable to the same property in base type 'FormGroup'.
  Type '<K extends Extract<keyof T, string>>(name: K, control: ControlType<T[K]>) => ControlType<T[K]>' is not assignable to type '(name: string, control: AbstractControl) => AbstractControl'.
    Types of parameters 'control' and 'control' are incompatible.
      Type 'AbstractControl' is not assignable to type 'ControlType<T[Extract<keyof T, string>]>'.

...

Package versions

@ng-stack/forms: 1.3.0
@angular/forms: 7.0.4

@tobiaskraus, thank you for reporting this issue. I have typescript@3.4.3 and your example actually detects a bug, but not exactly that you specified:

import { FormControl, FormGroup } from '@ng-stack/forms';

interface ValidationModel {
  wrongPassword?: { returnedValue: boolean };
  wrongEmail?: { returnedValue: boolean };
}

const form = new FormGroup<any, any>({
  control: new FormControl<any, ValidationModel>('some value'),
});

// Type 'FormControl<any, ValidationModel>' is not assignable to type 'FormGroup<any, ValidatorsModel> | FormControl<any, ValidatorsModel> | FormArray<any, ValidatorsModel>'.
//   Type 'FormControl<any, ValidationModel>' is not assignable to type 'FormControl<any, ValidatorsModel>'.
//     Type 'ValidationModel' is missing the following properties from type 'ValidatorsModel': min, max, required, requiredTrue, and 8 more.ts(2322)

TypeScript says about the compatibility issue of the default ValidatorsModel and the model that you passed - ValidationModel. This is a bug that I will try to solve.

As a hotfix, you can raise the ValidationModel to FormGroup:

const form = new FormGroup<any, ValidationModel>({
  control: new FormControl('some value'),
});

The error that you wrote probably relates to the mix of imports FormGroup, FormControl etc. from @ng-stack/forms and @angular/forms. Please check it out.

So, @tobiaskraus, you can now to use <any, any> to solve issues with nested validation model:

const form = new FormGroup<any, any>({
  control: new FormControl<any, ValidationModel>('some value'),
});

But this does not make much sense, use the validation model only for parent's control instead:

const form = new FormGroup<any, ValidationModel>({
  control: new FormControl('some value'),
});