Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError for FromGroup.removeControl #47306

Closed
fellmann opened this issue Aug 31, 2022 · 5 comments
Closed

TypeError for FromGroup.removeControl #47306

fellmann opened this issue Aug 31, 2022 · 5 comments

Comments

@fellmann
Copy link

Which @angular/* package(s) are the source of the bug?

forms

Is this a regression?

No

Description

FormControl.removeControl shows type error when TypeScript strictNullChecks is enabled.

const group = new FormGroup({"a": new FormControl("test")})
group.removeControl("a")

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-hy5qkn?file=tsconfig.json,src%2Fapp%2Fapp.component.ts

Please provide the exception or error you saw

Error in src/app/app.component.ts (14:5)
No overload matches this call.
Overload 1 of 2, '(this: FormGroup<{ [key: string]: AbstractControl<any, any>; }>, name: string, options?: { emitEvent?: boolean | undefined; } | undefined): void', gave the following error.
The 'this' context of type 'FormGroup<{ a: FormControl<string | null>; }>' is not assignable to method's 'this' of type 'FormGroup<{ [key: string]: AbstractControl<any, any>; }>'.
Property '"a"' is missing in type '{ [key: string]: AbstractControl<any, any>; }' but required in type '{ a: FormControl<string | null>; }'.
Overload 2 of 2, '(name: never, options?: { emitEvent?: boolean | undefined; } | undefined): void', gave the following error.
Argument of type 'string' is not assignable to parameter of type 'never'.

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 14.2.1
Node: 16.13.2
Package Manager: npm 8.5.5 
OS: win32 x64

Angular: 14.2.0
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router     

Package                         Version
---------------------------------------------------------  
@angular-devkit/architect       0.1402.1
@angular-devkit/build-angular   14.2.1
@angular-devkit/core            14.2.1
@angular-devkit/schematics      14.2.1
@angular/cli                    14.2.1
@schematics/angular             14.2.1
rxjs                            7.5.6
typescript                      4.8.2

Anything else?

No response

@JoostK
Copy link
Member

JoostK commented Aug 31, 2022

This is working as expected due to how typed forms has been designed. FormGroup infers its control type from the provided initial set of controls, such that "a" is inferred to be always present. This means that it becomes invalid to remove the control, as is now enforced through type-checking.

If you want to remove a control, then you'd need to declare an explicit control type where the "a" property is optional:

interface MyControlType {
  a?: FormControl<string>;
}

and then use that type when creating the FormGroup: new FormGroup<MyControlType>({ .. })

Alternatively, you could switch to the untyped API by importing UntypedFormGroup instead of FormGroup, although this means that you'll loose the strong typeing capabilities altogether.

@JoostK JoostK closed this as not planned Won't fix, can't repro, duplicate, stale Aug 31, 2022
@ngbot ngbot bot added this to the needsTriage milestone Aug 31, 2022
@fellmann
Copy link
Author

@JoostK That is a valid point, and I am sorry for giving a wrong example.

Consider this code:

    const controls1: { a?: FormControl<number> } = {};
    const group1 = new FormGroup(controls1);
    group1.removeControl('a');

    const controls2: { [key: string]: FormControl<number> } = {};
    const group2 = new FormGroup(controls2);
    group2.removeControl('a');

    const controls3: Record<string, FormControl<number>> = {};
    const group3 = new FormGroup(controls3);
    group3.removeControl('a');

    const controls4: { a: FormControl<number>; [additional: string]: FormControl<number> } = {
      a: new FormControl(3, { nonNullable: true }),
      b: new FormControl(3, { nonNullable: true }),
    };
    const group4 = new FormGroup(controls4);
    group4.removeControl('b');

Only the first example works, while the last three show the same type error.

It works as expected for 2 and 3 when adding | {} to the type:

    const controls2: { [key: string]: FormControl<number> } | {} = {};
    const group2 = new FormGroup(controls2);
    group2.removeControl("a");

    const controls3: Record<string, FormControl<number>> | {} = {};
    const group3 = new FormGroup(controls3);
    group3.removeControl('a');

@JoostK
Copy link
Member

JoostK commented Aug 31, 2022

In that case I think you're looking for FormRecord (new since typed forms) instead of FormGroup.

@fellmann
Copy link
Author

Thank you, that is the correct solution!

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Oct 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants