3
votes

My question here is; What's causing vscode to lose track of the type and if there is any way of extending it's capability. Secondarily any possible workaround would be appreciated.

I've done some googling and found a couple issues related to infinite type recursion getting abandoned but I'm not sure if this falls in that boat or not. If it is that I think this instance is pretty interesting given Rxjs is such a widely used library and this problem can be triggered after only 9 map calls in a given pipe.

https://github.com/microsoft/TypeScript/issues/35533
https://github.com/microsoft/TypeScript/issues/29511

See below for a simple code fragment that reproduces the issue in vscode.

import { Subject } from 'rxjs';
import { map } from 'rxjs/operators';

const test = new Subject<string>();

test.pipe(
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg),
  map(msg => msg) // <---- type is lost here, msg becomes any!
);
1
Looks like this is really just an Rxjs limitation here with only 9 possible piped operators with anything above that reverting back to any and returning Observable<{}>. If you'd like to formulate this as an answer we can wrap this thing up. - radman
The workaround is using a second pipe after 9 operators. test.pipe(9-operators).pipe(more-operators) - frido

1 Answers

1
votes

as @cartant mentioned rxjs-pipes gain types via overloads. As you can see the overloads are only applied up to 9 arguments (operators). To avoid loosing types you can chain multiple pipes:

const source$ = pipe(
  ...
  map(foo => foo),
  ...
).pipe(
  ...
  map(foo => foo),
  ...
)

Check the type of source$ in this running stackblitz.

Easy sample overload:

class Foo {
  add<T>(arg: T): T
  add<T, T2>(arg1: T, arg2: T2): T | T2
  add<T, T2>(arg1: T, arg2: T2, ...args: any): any
  add(...args: any) {
    return args.reduce((acc: any, curr: any) => acc + ' ' + curr, '')
  }
}

const foo = new Foo();

// type: 'first' | 'second'
const add1 = foo.add('first', 'second');
console.log(add1);

// type: any
const add2 = foo.add('first', 'second', 'third');
console.log(add2);

The example itself is stupid but I hope it explains the reason why it gets any at some point.