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

Improve typing of common pipes #37447

Closed
wants to merge 7 commits into from

Conversation

@ranma42
Copy link
Contributor

@ranma42 ranma42 commented Jun 4, 2020

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: #36259
Several pipes have incomplete or incorrect typing.

What is the new behavior?

The common pipes should now all have a stricter typing.

Does this PR introduce a breaking change?

  • Yes
  • No

It depends on what is considered a breaking change: some code that would compile will now trigger a compilation error. On the other hand, the code that is made invalid by this change, such as passing an object to a numeric pipe, was incorrect in the first place (it caused errors at runtime instead of at compile time).

Fixing the fallout should be trivial.

Other information

Originally posted as #36277

@pullapprove pullapprove bot requested review from kara, kyliau and mhevery Jun 4, 2020
@googlebot googlebot added the cla: yes label Jun 4, 2020
@kyliau kyliau requested review from petebacondarwin and removed request for kara Jun 4, 2020
@pullapprove pullapprove bot requested a review from kara Jun 4, 2020
@kyliau
Copy link
Member

@kyliau kyliau commented Jun 4, 2020

Thank you for reopening the PR @ranma42!

For context, this is a continuation of #36277. It was accidentally closed by me due to my silly mistake in git push!

@kyliau kyliau force-pushed the ranma42:fix/common-pipes-typing branch from 877401f to b490813 Jun 5, 2020
@kyliau kyliau requested a review from ayazhafiz Jun 5, 2020
@kyliau kyliau force-pushed the ranma42:fix/common-pipes-typing branch from b490813 to f0ac1ff Jun 5, 2020
@kyliau kyliau force-pushed the ranma42:fix/common-pipes-typing branch from f0ac1ff to 210e4c2 Jun 5, 2020
@ngbot ngbot bot added this to the needsTriage milestone Jun 5, 2020
@kyliau
Copy link
Member

@kyliau kyliau commented Jun 5, 2020

@ranma42 I've fixed up the language service part, should be good to go now.
@petebacondarwin Could you please take another look? Sorry I messed up the earlier PR and accidentally closed it.

@kyliau
kyliau approved these changes Jun 5, 2020
Copy link
Member

@kyliau kyliau left a comment

LGTM for language service

Copy link
Member

@petebacondarwin petebacondarwin left a comment

Apart from the additional suggested overloads, which IMO are optional for this PR, LGTM

Reviewed-for: fw-i18n

@@ -29,8 +29,10 @@ export class LowerCasePipe implements PipeTransform {
/**
* @param value The string to transform to lower case.
*/
transform(value: string): string {
if (!value) return value;
transform(value: string|null|undefined): string|null;

This comment has been minimized.

@petebacondarwin

petebacondarwin Jun 8, 2020
Member

Is it worth adding yet another overload of

transform(value: null|undefined): null;

This comment has been minimized.

@petebacondarwin

petebacondarwin Jun 8, 2020
Member

And similarly elsewhere.

(Disclaimer: I have not checked whether this would break the type system...)

This comment has been minimized.

@ranma42

ranma42 Jun 9, 2020
Author Contributor

I tried locally and it looks like it should be fine, apart from a couple of language-service tests that would need to be updated (they check that there is exactly one type for a pipe, while this change would make the resolver find two types).
Should I add it to this branch or is it better to do it in another PR?
In the first case, should I squash the changes or add them on top? (what is best for reviews/the convention for this repo?)

This comment has been minimized.

@ranma42

ranma42 Jun 9, 2020
Author Contributor

Is it worth adding yet another overload of

transform(value: null|undefined): null;

I had omitted them assuming that it is a niche use case, but it certainly makes typing more accurate and I guess it might help spotting issues in some buggy code.

This comment has been minimized.

@petebacondarwin

petebacondarwin Jun 9, 2020
Member

Not a blocker for this PR from my point of view. I just mention it because, this PR involves a public API change, and a second PR would also do so, which is extra work checking the API each time.

I would rather get @IgorMinar another public API approver to comment before you make any further changes.

@kyliau kyliau requested review from kara and removed request for kara, alxhub, IgorMinar and pkozlowski-opensource Jun 8, 2020
@pullapprove pullapprove bot requested a review from alxhub Jun 8, 2020
ranma42 added 7 commits Mar 27, 2020
…#36259)

The old implementation of case conversion types can handle several
values which are not strings, but the signature did not reflect this.

The new one reports errors when falsy non-string inputs are given to
the pipe (such as `false` or `0`) and has a new signature which
instead reflects the behaviour on `null` and `undefined`.

Fixes #36259

BREAKING CHANGE:
The case conversion pipes no longer let falsy values through. They now
map both `null` and `undefined` to `null` and raise an exception on
invalid input (`0`, `false`, `NaN`) just like most "common pipes". If
your code required falsy values to pass through, you need to handle them
explicitly.
`AsyncPipe.transform` will never return `undefined`, even when passed
`undefined` in input, in contrast with what was declared in the
overloads.

Additionally the "actual" method signature can be updated to match the
most generic case, since the implementation does not rely on wrappers
anymore.

BREAKING CHANGE:
The async pipe no longer claims to return `undefined` for an input that
was typed as `undefined`. Note that the code actually returned `null` on
`undefined` inputs. In the unlikely case you were relying on this,
please fix the typing of the consumers of the pipe output.
Make typing of DatePipe stricter to catch some misuses (such as passing
an Observable or an array) at compile time.

BREAKING CHANGE:
The signature of the `date` pipe now explicitly states which types are
accepted. This should only cause issues in corner cases, as any other
values would result in runtime exceptions.
Make typing of number pipes stricter to catch some misuses (such as
passing an Observable or an array) at compile time.

BREAKING CHANGE:
The signatures of the number pipes now explicitly state which types are
accepted. This should only cause issues in corner cases, as any other
values would result in runtime exceptions.
I18nPluralPipe can actually accept `null` and `undefined` (which are
convenient for composing it with the async pipe), but it is currently
typed to only accept `number`.
As shown in the tests, `KeyValuePipe.transform` can accept
`undefined`, in which case it always returns `null`.

Additionally, the typing for `string` keys can be made generic, so the
comparison function is only required to accept the relevant cases.

Finally, the typing for `number` records now shows that the comparison
function and the result entries will actually receive the string version
of the numeric keys, just as shown in the tests.

BREAKING CHANGE:
The typing of the `keyvalue` pipe has been fixed to report that for
input objects that have `number` keys, the result will contain the
string representation of the keys. This was already the case and the
code has simply been updated to reflect this. Please update the
consumers of the pipe output if they were relying on the incorrect
types. Note that this does not affect use cases where the input values
are `Map`s, so if you need to preserve `number`s, this is an effective
way.
Even in the overloads, state that it can accept `null` and
`undefined`, in order to ensure easy composition with `async`.

Additionally, change the implementation to return `null` on an
`undefined` input, for consistency with other pipes.

BREAKING CHANGE:
The `slice` pipe now returns `null` for the `undefined` input value,
which is consistent with the behavior of most pipes. If you rely on
`undefined` being the result in that case, you now need to check for it
explicitly.
@ranma42 ranma42 force-pushed the ranma42:fix/common-pipes-typing branch from 1d61f61 to 967dd3e Sep 23, 2020
@JoostK
JoostK approved these changes Sep 23, 2020
Copy link
Member

@JoostK JoostK left a comment

LGTM, thanks for putting this together!

@AndrewKushnir
Copy link
Contributor

@AndrewKushnir AndrewKushnir commented Sep 23, 2020

@alxhub alxhub closed this in c7d5555 Sep 28, 2020
alxhub added a commit that referenced this pull request Sep 28, 2020
`AsyncPipe.transform` will never return `undefined`, even when passed
`undefined` in input, in contrast with what was declared in the
overloads.

Additionally the "actual" method signature can be updated to match the
most generic case, since the implementation does not rely on wrappers
anymore.

BREAKING CHANGE:
The async pipe no longer claims to return `undefined` for an input that
was typed as `undefined`. Note that the code actually returned `null` on
`undefined` inputs. In the unlikely case you were relying on this,
please fix the typing of the consumers of the pipe output.

PR Close #37447
alxhub added a commit that referenced this pull request Sep 28, 2020
Make typing of DatePipe stricter to catch some misuses (such as passing
an Observable or an array) at compile time.

BREAKING CHANGE:
The signature of the `date` pipe now explicitly states which types are
accepted. This should only cause issues in corner cases, as any other
values would result in runtime exceptions.

PR Close #37447
alxhub added a commit that referenced this pull request Sep 28, 2020
Make typing of number pipes stricter to catch some misuses (such as
passing an Observable or an array) at compile time.

BREAKING CHANGE:
The signatures of the number pipes now explicitly state which types are
accepted. This should only cause issues in corner cases, as any other
values would result in runtime exceptions.

PR Close #37447
alxhub added a commit that referenced this pull request Sep 28, 2020
I18nPluralPipe can actually accept `null` and `undefined` (which are
convenient for composing it with the async pipe), but it is currently
typed to only accept `number`.

PR Close #37447
alxhub added a commit that referenced this pull request Sep 28, 2020
As shown in the tests, `KeyValuePipe.transform` can accept
`undefined`, in which case it always returns `null`.

Additionally, the typing for `string` keys can be made generic, so the
comparison function is only required to accept the relevant cases.

Finally, the typing for `number` records now shows that the comparison
function and the result entries will actually receive the string version
of the numeric keys, just as shown in the tests.

BREAKING CHANGE:
The typing of the `keyvalue` pipe has been fixed to report that for
input objects that have `number` keys, the result will contain the
string representation of the keys. This was already the case and the
code has simply been updated to reflect this. Please update the
consumers of the pipe output if they were relying on the incorrect
types. Note that this does not affect use cases where the input values
are `Map`s, so if you need to preserve `number`s, this is an effective
way.

PR Close #37447
alxhub added a commit that referenced this pull request Sep 28, 2020
Even in the overloads, state that it can accept `null` and
`undefined`, in order to ensure easy composition with `async`.

Additionally, change the implementation to return `null` on an
`undefined` input, for consistency with other pipes.

BREAKING CHANGE:
The `slice` pipe now returns `null` for the `undefined` input value,
which is consistent with the behavior of most pipes. If you rely on
`undefined` being the result in that case, you now need to check for it
explicitly.

PR Close #37447
@AndrewKushnir
Copy link
Contributor

@AndrewKushnir AndrewKushnir commented Sep 28, 2020

Hi @ranma42, just want to let you know that this PR was merged into master branch and the change will be included into upcoming v11 release. Thank you for contributing to Angular!

AndrewKushnir added a commit to AndrewKushnir/igniteui-angular that referenced this pull request Sep 29, 2020
… in Angular Pipes

There is an upcoming improvement in common pipes in Angular framework that would be released in the next major version (v11). The changes can be found in angular/angular#37447.

This commit refactors `IgxDatePipeComponent` and `IgxDecimalPipeComponent` pipes to provide forward-compatibility for the next major release of Angular framework. The improved typings make `transform` function signatures of the mentioned pipes incompatible with the `DatePipe` and `DecimalPipe`. This commit updates the mentioned pipes to initialize `DatePipe` and `DecimalPipe` in constructors instead of extending them (to keep existing `transform` function signatures) and use created instances inside the `transform` function as needed.
AndrewKushnir added a commit to AndrewKushnir/delon that referenced this pull request Sep 29, 2020
…ular Pipes

There is an upcoming improvement in common pipes in Angular framework that would be released in the next major version (v11). The changes can be found in angular/angular#37447.

This commit refactors the `CNCurrencyPipe` pipe to provide forward-compatibility for the next major release of Angular framework. The improved typings make `transform` function signature of the mentioned pipe incompatible with the `CurrencyPipe`. This commit updates the `CNCurrencyPipe` pipe to initialize the `CurrencyPipe` in constructor instead of extending it (to keep existing `transform` function signature) and use created instance inside the `transform` function as needed.
AndrewKushnir added a commit to AndrewKushnir/delon that referenced this pull request Sep 29, 2020
…ular Pipes

There is an upcoming improvement in common pipes in Angular framework that would be released
in the next major version (v11). The changes can be found in
angular/angular#37447.

This commit refactors the `CNCurrencyPipe` pipe to provide forward-compatibility for the next
major release of Angular framework. The improved typings make `transform` function signature
of the mentioned pipe incompatible with the `CurrencyPipe`. This commit updates the
`CNCurrencyPipe` pipe to initialize the `CurrencyPipe` in constructor instead of extending it
(to keep existing `transform` function signature) and use created instance inside the `transform`
function as needed.
AndrewKushnir added a commit to AndrewKushnir/delon that referenced this pull request Sep 29, 2020
…ular Pipes

There is an upcoming improvement in common pipes in Angular framework that would be released
in the next major version (v11). The changes can be found in
angular/angular#37447.

This commit refactors the `CNCurrencyPipe` pipe to provide forward-compatibility for the next
major release of Angular framework. The improved typings make `transform` function signature
of the mentioned pipe incompatible with the `CurrencyPipe`. This commit updates the
`CNCurrencyPipe` pipe to initialize the `CurrencyPipe` in constructor instead of extending it
(to keep existing `transform` function signature) and use created instance inside the `transform`
function as needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.