Skip to content

[WIP] feat(forms): add generic typings to AbstractControl - #16828

Closed
Toxicable wants to merge 1 commit into
angular:masterfrom
Toxicable:generic-formcontrol
Closed

[WIP] feat(forms): add generic typings to AbstractControl#16828
Toxicable wants to merge 1 commit into
angular:masterfrom
Toxicable:generic-formcontrol

Conversation

@Toxicable

@Toxicable Toxicable commented May 16, 2017

Copy link
Copy Markdown

Please check if the PR fulfills these requirements

  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

What is the current behavior?
#13721 Currently there is no generic type support for AbstractControl
Therefore AbstractControl#value will always return a value with type: any

What is the new behavior?
Provides type support for AbstractControl#value and related fields/methods

For example:

const control = new FormControl('Toxicable');
const value = control.value;
const changes = control.valueChanges;

In this example control will be control: FormControl<string>
value will be value: string
changes will be changes: Observable<string>

Does this PR introduce a breaking change? (check one with "x")

[ x ] Yes
[ ] No

The breaking change is the TS2.3 requirement for default generics
With default generics it means we are able to make these changes without breaking the API surface
For example:

const control = new FormControl();
const value = control.value;

Here control will be control: FormControl<any>
value will be value: any
Which is the same behavior as the API currently provides

However. If someone is misusing the API like below, then it will indeed break their code

const control = new FormControl('Toxicable');
control.value.toFixed(3); //the user might be using the string as a number

This will throw with the TS compiler since it will now infer the type and know that control.value is a string

closes #13721

cc @kara

@googlebot

Copy link
Copy Markdown

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.

@Toxicable Toxicable closed this May 16, 2017
@Toxicable
Toxicable force-pushed the generic-formcontrol branch from 83399bc to 9a7f5d5 Compare May 16, 2017 22:12
@Toxicable Toxicable reopened this May 16, 2017
@googlebot

Copy link
Copy Markdown

CLAs look good, thanks!

@Toxicable
Toxicable force-pushed the generic-formcontrol branch from ce1a6bf to 8bb157b Compare May 17, 2017 08:15
@Toxicable Toxicable changed the title [WIP] feat(forms): make AbstractControl generic [WIP] feat(forms): add generic typings to AbstractControl May 17, 2017
@Toxicable
Toxicable force-pushed the generic-formcontrol branch 4 times, most recently from b545ef4 to dec1f15 Compare May 17, 2017 10:15
@Toxicable Toxicable changed the title [WIP] feat(forms): add generic typings to AbstractControl feat(forms): add generic typings to AbstractControl May 17, 2017
@Toxicable

Copy link
Copy Markdown
Author

The error in Travis is that one of the e2e tests hasn't been upgraded to TS2.3, that's why it's expecting a , on <T = any>

Comment thread packages/forms/src/model.ts Outdated

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im open for suggestions on how to default formState to null a bit nicer than what I got going on here

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Toxicable maybe we can add default value (null) to formState?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did attempt to make it default to null but was unable to satisfy the TS compiler

@Toxicable Toxicable May 17, 2017

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this for testing the generics to make sure they can infer the correct things and will remove before done. If there's any specific behavior that isn't already tested then i'll add a specific test for it.

Comment thread packages/forms/src/model.ts Outdated

@Toxicable Toxicable May 17, 2017

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the signature now allows nulls we should do a proper null check here

@Toxicable
Toxicable force-pushed the generic-formcontrol branch from dec1f15 to 48df0b6 Compare May 17, 2017 11:06
@devoto13

Copy link
Copy Markdown
Contributor

While I'm really looking forward for this PR to be merged, it will require Angular to stop supporting TS <2.3. So it may be considered a breaking change and require a major version bump... On the other hand updating from 2.1 and 2.2 shouldn't require changes in the application, so hopefully we can get it in the next minor.

@Toxicable

Toxicable commented May 17, 2017

Copy link
Copy Markdown
Author

@devoto13 Ahh right, I overlooked the need to upgrade to TS 2.3. Which means this is indeed a breaking change since people on TS 2.1 which Angular does currently support would have a broken build with this PR. However, it's possible that Angular will require TS2.3 in other areas by v5 which would be the next suitable point to merge this into

@desfero

desfero commented May 20, 2017

Copy link
Copy Markdown

Maybe we could add generic default for AbstractControl#get method? Currenly it always return AbstractControl.

@Toxicable

Toxicable commented May 20, 2017

Copy link
Copy Markdown
Author

@desfero I havn't been able to make types that allows the lookups of AbstractControl#get for what type of control should be returned but once I solve the issue currently blocking this PR I will continue investigating how we might make this more ergonomic

Comment thread packages/forms/src/model.ts Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Toxicable maybe we can add default value (null) to formState?

Comment thread packages/forms/src/model.ts Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Toxicable is it some kind of good practice to have space between value and ![name]

@Toxicable Toxicable May 21, 2017

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting isn't my choosing, it's as per Angular's Formatting build scripts, however in this case I don't think it's updated to handle variable![prop].

@desfero

desfero commented May 21, 2017

Copy link
Copy Markdown

@Toxicable yes, you are right, we cannot lookup in the type, but programmer could explicitly specify that 'name' is for e.g. MyCustomFormControl, please have a look at #16769

@Toxicable

Toxicable commented May 21, 2017

Copy link
Copy Markdown
Author

@desfero oh right, totally overlooked giving it it's own generic, feels pretty janky but I don't think there's another option currently, ill add that in and will continue to look at how it might be improved

@Toxicable
Toxicable force-pushed the generic-formcontrol branch from 48df0b6 to e6a7a6e Compare May 21, 2017 08:20
@Toxicable Toxicable changed the title feat(forms): add generic typings to AbstractControl [WIP] feat(forms): add generic typings to AbstractControl Jun 2, 2017
@Toxicable

Copy link
Copy Markdown
Author

Blocked on microsoft/TypeScript#16229 for the time being

@googlebot

Copy link
Copy Markdown

So there's good news and bad news.

馃憤 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

馃槙 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that they're okay with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of the commit author(s) and merge this pull request when appropriate.

@Toxicable
Toxicable force-pushed the generic-formcontrol branch from c03622f to 83beeae Compare July 24, 2017 20:07
@googlebot

Copy link
Copy Markdown

CLAs look good, thanks!

@Toxicable

Copy link
Copy Markdown
Author

I just had another look at this and I don't think it's possible on the current Forms API.
There is an issue where if initialize a FormControl to null with strictNullChecks enabled then the generic will be inferred as null which means that it could cause breaking changes which was what we were aiming to avoid here.
Example here:

//inferred as: control: FormControl<null>
var control = FormControl(null);

//err: string != null
control.setValue('Toxicable');

So I'm closing this since I don't think it's possible to not cause breaking changes on the current Forms API

@Toxicable Toxicable closed this Oct 16, 2017
@xnnkmd

xnnkmd commented Oct 30, 2017

Copy link
Copy Markdown

@Toxicable What about changing default generics type to T = object ? Would that help?

@Toxicable

Copy link
Copy Markdown
Author

@xnnkmd nope it would have the same effect

@Toxicable

Copy link
Copy Markdown
Author

@xnnkmd

xnnkmd commented Oct 30, 2017

Copy link
Copy Markdown

@Toxicable Sorry, the link does not work. Here is the suggested code:

class FormControl<T extends Object = object>{
    constructor(public value: T | null) { }
}
var c = new FormControl(null)
c.value = 'Toxicable';

@xnnkmd

xnnkmd commented Oct 30, 2017

Copy link
Copy Markdown

@Toxicable This alternative also works for your example (need more test cases to be sure what works best and to check it does work in all cases):

class FormControl<T extends Object = object | number | string | symbol | boolean>{
    constructor(public value: T | null) { }
}
var c = new FormControl('x')
c.value = 'Toxicable';

@Toxicable

Copy link
Copy Markdown
Author

Superseded by #20040

@angular-automatic-lock-bot

Copy link
Copy Markdown

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 Sep 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reactive forms are not strongly typed

6 participants