javascript - Typescript discriminated union types with Rx.js filter operator? - Stack Overflow

Typescript supports discriminated unions. How to extend the same concept with Rxjs to the filter operat

Typescript supports discriminated unions. How to extend the same concept with Rxjs to the filter operator in below example?

interface Square {
    kind: 'square';
    width: number;
}

interface Circle {
    kind: 'circle';
    radius: number;
}

interface Center {
    kind: 'center';
}

type Shape = Square | Circle | Center;

const obs$: Observable<Shape> = of<Shape>({ kind: 'square', width: 10 });

// Expected type: Observable<Square>
// Actual type: Observable<Shape>
const newObs$ = obs$.pipe(
    filter((x) => x.kind === 'square')
);

I above code snippet, I would want to see newObs$ to have its type inferred as: Observable<Square>. But apparently, TypeScript doesn't do that.

How to achieve this? Am I reaching the limits of TypeScript type inference?

I look for this as it seems to be very useful in a Redux + Redux-Observable codebase.

Typescript supports discriminated unions. How to extend the same concept with Rxjs to the filter operator in below example?

interface Square {
    kind: 'square';
    width: number;
}

interface Circle {
    kind: 'circle';
    radius: number;
}

interface Center {
    kind: 'center';
}

type Shape = Square | Circle | Center;

const obs$: Observable<Shape> = of<Shape>({ kind: 'square', width: 10 });

// Expected type: Observable<Square>
// Actual type: Observable<Shape>
const newObs$ = obs$.pipe(
    filter((x) => x.kind === 'square')
);

I above code snippet, I would want to see newObs$ to have its type inferred as: Observable<Square>. But apparently, TypeScript doesn't do that.

How to achieve this? Am I reaching the limits of TypeScript type inference?

I look for this as it seems to be very useful in a Redux + Redux-Observable codebase.

Share Improve this question edited May 25, 2018 at 9:55 Harshal Patil asked May 25, 2018 at 8:44 Harshal PatilHarshal Patil 21.2k16 gold badges73 silver badges150 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 8

Actually you can do this with TypeScript type guards. See section "Type Guards and Differentiating Types" at http://www.typescriptlang/docs/handbook/advanced-types.html

The key here is the function isWhatever(x: any): x is Whatever => ... syntax.

This basically says that if the isWhatever function returns true then it guarantees that x is of Whatever type.

In your example TypeScript considers all three classes:

So you can define the predicate function for filter() as this:

filter((x: Shape): x is Square => x.kind === 'square')

Now it will properly consider only the Square class:

See live demo: https://stackblitz./edit/rxjs6-demo-z9lwxe?file=index.ts

Very similar question: https://github./ReactiveX/rxjs/issues/2340

This is not necessarily a limitation with the TypeScript type system but rather with the implementation of filter. You can easily achieve the desired behaviour using flatMap:

// Inferred type: Observable<Square>
const newObs$ = obs$.pipe(
  flatMap((x) => x.kind === "square" ? of(x) : empty())
);

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745547977a4632429.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信