In composing an observable stream, returning a tuple from the map function is inferred by the compiler as a union instead of a tuple.
For example:
import { Component } from '@angular/core';
import { from } from 'rxjs';
import { map, tap } from 'rxjs/operators';
export class MyType {
constructor(private name: string) {}
}
@Component({
selector: 'my-app',
template: ''
})
export class AppComponent {
observable$ = from([new MyType('obj1'), new MyType('obj2')]).pipe(
map((value, index) => [value, index]),
tap(([value, index]) => console.log(value, index))
).subscribe();
}
Check it out on stackblitz, if you hover over value or index in the function parameter in tap, they both get inferenced to number | MyType when it should understand that value: MyType and index: number.
if I annotate map by filling in the generics: map<MyType, [MyType, number]>(... then the typing is correct.
Is this the expected behavior? Shouldn't typescript understand that tuple without having to explicitly pass the type?
I'm using rxjs @ 6.4.0 and typescript @ 3.8.3 locally, but stackblitz has more recent versions and still presents this behavior.
CodePudding user response:
In your map function, you are returning an array, not tuple.
You can use as const to force the tuple type:
export class AppComponent {
observable$ = from([new MyType('obj1'), new MyType('obj2')]).pipe(
map((value, index) => [value, index] as const),
tap(([value, index]) => console.log(value, index))
).subscribe();
}
See Tuple Types:
array literals with
constassertions will be inferred withreadonlytuple types
