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

fix(reduce): fix overload ordering #2382

Merged
merged 4 commits into from
Apr 3, 2017
Merged

fix(reduce): fix overload ordering #2382

merged 4 commits into from
Apr 3, 2017

Conversation

aluanhaddad
Copy link
Contributor

Description:
Type inference for Observable.prototype.reduce currently behaves incorrectly, resulting in spurious type errors, in many common cases, when the type of seed is a different type than the value type of the Observable.

One of the declared overloads is intended to specifically cater to this scenario but fails to do so because of its ordering with respect to the other overload declared.

The overload in question takes two type arguments, T and R, making it more specific than the overloads declared before it.

Due to TypeScript's overload resolution algorithm, which picks the first matching overload, this overload does not have the intended effect.

This is documented here https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html in the section entitled Function Overloads, under the Ordering heading, which states

Don’t put more general overloads before more specific overloads:

Do sort overloads by putting the more general signatures after more specific signatures:

Why: TypeScript chooses the first matching overload when resolving function calls. When an earlier overload is “more general” than a later one, the later one is effectively hidden and cannot be called.

Related issue (if exists):
This fixes #2338

Copy link
Member

@kwonoj kwonoj left a comment

Choose a reason for hiding this comment

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

Looks good to me, but would you mind add some test cases failing before and fixed by this PR?

@aluanhaddad
Copy link
Contributor Author

@kwonoj Thank you, I most definitely will.

@aluanhaddad
Copy link
Contributor Author

aluanhaddad commented Feb 17, 2017

It looks like there is more nuance here, the overload taking an array seems to be producing more issues than I had thought.

Actually no it is just that the assumptions about where the type argument inference for seed actually comes from in the failing test cases seem incorrect.

@rxjs-bot
Copy link

rxjs-bot commented Feb 17, 2017

Warnings
⚠️ commit message does not follows conventional change log (1)

(1) : RxJS uses conventional change log to generate changelog automatically. It seems some of commit messages are not following those, please check contributing guideline and update commit messages.

Generated by 🚫 dangerJS

@benlesh
Copy link
Member

benlesh commented Feb 20, 2017

@aluanhaddad it looks like there are build errors with the specs. Do you think you can fix them?

@aluanhaddad
Copy link
Contributor Author

Yes I've been very busy recently. I will try to fix them tonight and add some additional tests as well. When I looked at the specs, they seemed to rely on the seed being inferred to have the value type of the Observable. I need to double-check if that is the case.
Perhaps I misunderstand the behavior of RxJS or the intent of the Declarations but this doesn't seem like a reasonable assumption at face value.

…iling specs

This adds tests for both existing behavior, under the old overload, and the new behavior enabled by the new overload signatures of the `reduce` operator.
Not that the specific change to the following test case `'should accept T typed reducers'` that removes the seed value. If a seed value is specified, then the reduction is always from `T` to `R`. This was necessary to make the test pass, but also models the expected behavior more correctly.

The cases for `R` where `R` is not assignable to `T` are covered by new tests added in the commit.

Additionally, I have added additional verification to all of the tests touched by this change to ensure that the values returned are usable as their respective expected types.
@aluanhaddad
Copy link
Contributor Author

aluanhaddad commented Feb 21, 2017

I am having some trouble replicating the test failures locally.
When I run

npm run build_spec && npm run test_mocha && node ./node_modules/markdown-doctest/bin/cmd.js

Any tips would be greatly appreciated.
node -v: 7.3.0
npm -v: 4.1.2
Windows 10 x64

Nevermind, I got it working.

Fix ordering as allowed by newly required seeds to fix failing tests.
I think there is a good argument to be made that the failing tests were failing correctly, as this is how `Array.prototype.reduce` behaves, but as I have made the seed arguments required, for `R` typed reducers, re-ordering the overloads impacts their specificity allowing, the current behavior, correct or otherwise, to be retained.
@coveralls
Copy link

coveralls commented Feb 21, 2017

Coverage Status

Coverage remained the same at 97.688% when pulling 99fd39d on aluanhaddad:patch-1 into 023d436 on ReactiveX:master.

@aluanhaddad
Copy link
Contributor Author

@kwonoj I added several new test including tests covering behavior that was an error before these changes.
@Blesh I fixed the failing tests and also broke them down into multiple discrete tests, for assignability.

I added a local binding and a subsequent statement to each test I touched so that the resulting value is now used in such a way that it validates that the types are propagated.

Let me know if these tests are sufficient and also let me know if I should have added the same tests to spec/operator/scan-spec.

@kwonoj
Copy link
Member

kwonoj commented Mar 12, 2017

I think this change is ready, re-approving. /cc @david-driscoll for second eye just in case.

type(() => {
let a: Rx.Observable<{ a: number; b: string }>;
a.reduce<{ a?: number; b?: string }>((acc, value) => {
const reduced = a.reduce<{ a?: number; b?: string }>((acc, value) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is a separate test required for generic type argument inference of R?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe so. Failure to infer R as distinct from T and T[] was the original issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

@aluanhaddad This test doesn't seem to be verifying correct inference, because it specifies the generic type arg explicitly. Probably for an inference test you'd repeat this without the explicit type argument, then try to assign reduced to a variable of the explicit type you expect to have been inferred.

Copy link
Contributor

Choose a reason for hiding this comment

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

My bad, just realized the "R is not assignable to T" test already covers inference. 👍

@masaeedu
Copy link
Contributor

lgtm

@benlesh
Copy link
Member

benlesh commented Mar 21, 2017

@david-driscoll can you review this please? <3

Copy link
Member

@david-driscoll david-driscoll left a comment

Choose a reason for hiding this comment

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

I have no idea how I missed this after being pinged several times... 👍

@aluanhaddad
Copy link
Contributor Author

Just to note, when I first looked at this, I believed the issue was simply due to the overload ordering but the root cause turned out to have as much to do with the optionality of the seed arguments as signature ordering. The now required seed arguments eliminate a previously applicable overload from the candidate set, but a minor order change was still ultimately necessary.

@benlesh
Copy link
Member

benlesh commented Apr 3, 2017

Thanks @aluanhaddad !!!

@lock
Copy link

lock bot commented Jun 6, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 6, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reduce logs as array, but erroring as object
7 participants