-
Notifications
You must be signed in to change notification settings - Fork 3k
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(scan-operator): Remove redundant function overload types for .scan #2897
Conversation
…perator Remove redundant function overloads for the scan operator which fixes the return type when dealing with a observable returning a union type. None
Generated by 🚫 dangerJS |
We intentionally introduced those specific signature via #1847 - I'm adding @david-driscoll to review this. |
I tend to agree with @hsubra89, it does look redundant. Perhaps it just helps less robust type inference in TS 2.0? Maybe we could remove this once we get to v6 and we're targetting TS 2.5+? |
@benlesh Those example screenshots I posted above was using Rxjs's typescript version which is 2.0.10. I'm not really sure about this, but if the type inference worked with one generic parameter in the first place, wouldn't it continue to work in this scenario? |
I don't recall legacy history but that looks legit explanation. What about target this into |
Actually, i've just noticed that there are a few incorrect tests in |
PR that fixes tests in scan-spec.ts #2902 |
This PR's removal of the first two overload signatures creates a problem - albeit one that those overloads don't specifically address. With only the last signature, if the optional seed is not specified, The problem can be fixed by adding a single additional signature to the change proposed in this PR and by making the /* tslint:disable:max-line-length */
export function scan<T>(this: Observable<T>, accumulator: (acc: T, value: T, index: number) => T): Observable<T>;
export function scan<T, R>(this: Observable<T>, accumulator: (acc: R, value: T, index: number) => R, seed: R): Observable<R>;
/* tslint:enable:max-line-length */ That is, if there is no seed, the accumulator and resultant observable must be of type Also, a similar PR is required for |
@benlesh @kwonoj Now that the tests PR has been merged, I attempted to reconcile the changes in this PR with those tests and what they represent. We can't really achieve that using TS 2.0. We wouldn't need any of these overloads for more recent versions of TS. In light of that, Should we close this PR and create a new PR that targets a more recent version of TS? |
@cartant Yep, Making these changes from this PR or the ones that @cartant suggested would break current codebases relying on the behaviour where both the seed and the value represent type If we're happy to push this into a minor release where there could potentially be breaking changes to current users of |
@hsubra89 I'm wrong: the first overload is required as-is. Otherwise, code like this: const reduced = a.reduce<{ a?: number; b?: string }>((acc, value) => {
value.a = acc.a;
...
return acc;
}, {}); will only match the overload with Interestingly, if only the second array-related overload is removed, everything is fine (with TypeScript 2.0.10). So it seems that the second overload is the redundant one. |
@cartant We can't really delete the array related one either : let a: Rx.Observable<{ a: number; b: string }>;
a.scan((acc, value) => acc.concat(value), []); In the example above, with the array related overload, the type of IMHO, the current implementation is wrong, but turning it into an There are much more elegant ways to handle this in more recent versions of TS. i.e, we could do something like this to allow it. Untested export function scan<T, R = T>(this: Observable<T>, accumulator: (acc: R, value: T, index: number) => R, seed?: T | R): Observable<R> { ... |
@hsubra89 Yeah, you are right. I've been having another look at this, this afternoon. Unfortunately, I can't seem to get it out of my head. Perhaps I should just go for a walk? And, yes, the signature that uses the more up-to-date TypeScript functionality is better. I've been doing some tinkering with a simple harness and it seems that TypeScript 2.0 and 2.5 behave in radically different ways depending upon the presence of the second overload. It needs to be there for 2.0 and needs to be removed for 2.5. I think a signature more like that proposed in your most recent comment would be the best option, if the TypeScript dependency can be bumped to a sufficiently recent version when the next major version of RxJS is released. Anyway, maybe now I can start thinking about something else. |
It seems like we should add signatures with the required seed as @cartant suggested, and one explicitly for the no-seed case. scan<T, R>(this: Observable<T>, accumulator: (acc: R, value: T, index: number) => R): Observable<R>
scan<T, R>(this: Observable<T>, accumulator: (acc: R, value: T, index: number) => R, seed: R): Observable<R> Because in one, the type should be inferred from the return value, and in the other, it's inferred from the seed. I'm not sure we care about the folks that are going to alter the type at each iteration through, we can assume they're just going to type things with Thoughts, @kwonoj? @david-driscoll? |
@benlesh Unfortunately, with the first signature const source = Rx.Observable.of(1, 2, 3);
const scanned: source.scan((acc, value) => value.toString()); The inferred type of Only if the type is specified for the const source = Rx.Observable.of(1, 2, 3);
const scanned: source.scan((acc: string, value) => value.toString()); (This is using TypeScript 2.5.3.) |
I can't be sure I can reliably guarantee this PR works without breaking regressions in 5. Personally would like hold off and revisit in v6. |
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. |
This PR removes redundant function overloads for the
.scan
operator. It also fixes the type inference when dealing with a source observable representingunion
types. i.e Consider the following =>Current Inferred type
Inferred type with the changes from this PR.