Typescript支持discriminated unions。 如何在下面的示例中将Rxjs的相同概念扩展到filter
运算符?
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')
);
我在上面的代码片段中,我希望看到newObs $将其类型推断为:Observable<Square>
。但显然,TypeScript
并没有这样做。
如何实现这一目标?我是否达到了TypeScript类型推断的极限?
我在寻找这个,因为它似乎在Redux + Redux-Observable
代码库中非常有用。
答案 0 :(得分:4)
实际上,您可以使用TypeScript类型防护来执行此操作。请参阅http://www.typescriptlang.org/docs/handbook/advanced-types.html
中的“类型保护和区分类型”部分这里的关键是function isWhatever(x: any): x is Whatever => ...
语法。
这基本上表明,如果isWhatever
函数返回true
,则可以保证x
属于Whatever
类型。
在您的示例中,TypeScript会考虑所有三个类:
因此,您可以为filter()
定义谓词函数:
filter((x: Shape): x is Square => x.kind === 'square')
现在它将只考虑Square
类:
查看现场演示:https://stackblitz.com/edit/rxjs6-demo-z9lwxe?file=index.ts
答案 1 :(得分:0)
这不一定是TypeScript类型系统的限制,而是filter
的实现。您可以使用flatMap
:
// Inferred type: Observable<Square>
const newObs$ = obs$.pipe(
flatMap((x) => x.kind === "square" ? of(x) : empty())
);