Current Behavior
When using reduce/scan, typings get lost on 6.3.1 version of rxjs
锘匡豢index.ts:5:27 - error TS2345: Argument of type 'MonoTypeOperatorFunction<any[]>' is not assignable to parameter of type 'OperatorFunction<string, any[]>'.
Types of parameters 'source' and 'source' are incompatible.
Type 'Observable<string>' is not assignable to type 'Observable<any[]>'.
Type 'string' is not assignable to type 'any[]'.
5 return from(items).pipe(reduce((acc, item) => acc.concat([item]), []));
Reproduction
import { from, Observable } from "rxjs";
import { reduce } from "rxjs/operators";
function load(items: string[]): Observable<string[]> {
return from(items).pipe(reduce((acc, item) => acc.concat([item]), []));
}
Expected behavior
It should not throw the typing error when trying to reduce.
Environment
tl;dr: I'm pretty sure this isn't a bug, and I think your code was getting around typechecking due to a bug in rxjs 6.2.1. I believe you need to be explicit about the types passed to reduce, and the following should type check and work correctly under rxjs 6.3.x+:
function load(items: string[]): Observable<string[]> {
return from(items).pipe(reduce((acc, item: string) => acc.concat([item]), []));
}
(change is item: string instead of just item)
Full explanation (disclaimer - I don't work on rxjs, I just enjoy figuring this stuff out and I could be wrong):
I believe your code was getting around correct typing using the funky pipe<R>(...operations: OperatorFunction<any, any>[]): Observable<R>; pipe overload added in https://github.com/ReactiveX/rxjs/pull/3789 and removed in https://github.com/ReactiveX/rxjs/pull/3945 .
If you take your code under rxjs 6.2.2 and change it to:
function load(items: string[]): Observable<string[]> {
const thingToReturn = from(items).pipe(reduce((acc, item) => acc.concat([item]), []));
return thingToReturn;
}
You'll notice there's an error, because thingToReturn is an Observable<{}> (similarly removing the explicit Observable<string> return type annotation changes the fn return type to Observable<{}>).
I think what's happening in 6.2.2 is something along the lines of:
reduce<any[]>(args): MonoTypeOperatorFunction<any[]> (under any rxjs version). If you mouse over reduce in your code you get reduce<any[]>..., and mouse over the item arg to see that it is similarly any[], when it should actually be string.Observable<string> return type and the errant pipe overload, to decide that you are calling .pipe<string[]>(op). The bad overload makes TS not care what the actual type params were for your reduce.In 6.3 the bad overload is gone, the inference doesn't happen even with the expression in the return, and TS errors because your reduce has type param any[], but pipe wants an operator with input of string.
In this case you need to tell TS explicitly that you are not using reduce<any[]> and are instead using reduce<string, string[]>. You can do this like reduce((acc, item: string) => acc.concat([item]), []) or reduce<string, string[]>((acc, item) => acc.concat([item]), []).
I'm not sure if there's anything that can be done in reduce.ts to allow TS to better infer when the two-type-param overload is wanted without the usage having to be specific. I don't think there is, but I could easily be missing something!
@jgbpercy
Great! This works for me. And your explanation is heuristic.
Most helpful comment
tl;dr: I'm pretty sure this isn't a bug, and I think your code was getting around typechecking due to a bug in rxjs 6.2.1. I believe you need to be explicit about the types passed to reduce, and the following should type check and work correctly under rxjs 6.3.x+:
(change is
item: stringinstead of justitem)Full explanation (disclaimer - I don't work on rxjs, I just enjoy figuring this stuff out and I could be wrong):
I believe your code was getting around correct typing using the funky
pipe<R>(...operations: OperatorFunction<any, any>[]): Observable<R>;pipe overload added in https://github.com/ReactiveX/rxjs/pull/3789 and removed in https://github.com/ReactiveX/rxjs/pull/3945 .If you take your code under rxjs 6.2.2 and change it to:
You'll notice there's an error, because thingToReturn is an
Observable<{}>(similarly removing the explicitObservable<string>return type annotation changes the fn return type toObservable<{}>).I think what's happening in 6.2.2 is something along the lines of:
reduce<any[]>(args): MonoTypeOperatorFunction<any[]>(under any rxjs version). If you mouse over reduce in your code you getreduce<any[]>..., and mouse over the item arg to see that it is similarlyany[], when it should actually bestring.Observable<string>return type and the errant pipe overload, to decide that you are calling.pipe<string[]>(op). The bad overload makes TS not care what the actual type params were for your reduce.In 6.3 the bad overload is gone, the inference doesn't happen even with the expression in the return, and TS errors because your reduce has type param
any[], but pipe wants an operator with input ofstring.In this case you need to tell TS explicitly that you are not using
reduce<any[]>and are instead usingreduce<string, string[]>. You can do this likereduce((acc, item: string) => acc.concat([item]), [])orreduce<string, string[]>((acc, item) => acc.concat([item]), []).I'm not sure if there's anything that can be done in reduce.ts to allow TS to better infer when the two-type-param overload is wanted without the usage having to be specific. I don't think there is, but I could easily be missing something!