Home > Blockchain >  Why can't typescript infer tuple return type in RxJs stream?
Why can't typescript infer tuple return type in RxJs stream?

Time:01-19

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 const assertions will be inferred with readonly tuple types

  •  Tags:  
  • Related