Home > Back-end >  TypeCasting in RxJS Operators
TypeCasting in RxJS Operators

Time:11-03

I'm trying to perform typecasting in the following scenario:

of(1, 2, 3, "not a number")
  .pipe(
    filter((val) => typeof val === "number"),
    map((number) => number * 2)
  )
  .subscribe();

Inside the map operator the number parameter is of type number, because the array values were filtered. However, typescript is not able to pick this up by itself and it says that the type of number inside the map is string|number. I tried to do typecasting in the following ways, but none of them is working.

Attempt 1:

of(1, 2, 3, "string")
  .pipe(
    filter((val) => typeof val === "number") as number,
    map((number) => number * 2)
  )
  .subscribe();

Error -> Argument of type 'number' is not assignable to parameter of type 'OperatorFunction<string | number, unknown>'.ts(2345)

Attempt 2:

of(1, 2, 3, "string")
  .pipe(
    filter((val) => typeof val === "number") as OperatorFunction<number,any>,
    map((number) => number * 2)
  )
  .subscribe();

Error -> Argument of type 'OperatorFunction<number, any>' is not assignable to parameter of type 'OperatorFunction<string | number, any>'. Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'.ts(2345)

Attempt 3:(set the return type in the pipe)

of(1, 2, 3, "string")
  .pipe<number, number>(
    filter((val) => typeof val === "number"),
    map((number) => number * 2)
  )
  .subscribe();

Error -> Argument of type 'MonoTypeOperatorFunction<string | number>' is not assignable to parameter of type 'OperatorFunction<string | number, number>'. Type 'Observable<string | number>' is not assignable to type 'Observable'. Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'.ts(2345)

(Valid, but too hacky) Attempt 4: This attempt is the only one that works, but it looks too hacky, as inside the map operator I can set any type to the parameter number since the return type of fitler was marked as any .

of(1, 2, 3, "string")
  .pipe(
    filter((val) => typeof val === "number") as any,
    map((number: number) => number * 2)
  )
  .subscribe();

CodePudding user response:

You need to add typeguard predicate val is number to the filter callback to narrow the type

of(1, 2, 3, "string")
  .pipe(
    filter((val): val is number => typeof val === "number"),
    map((number) => number * 2)
  )
  .subscribe();

More about type guards in the typescript docs

github issue

  • Related