使用Rx.js过滤运算符的Typescript区分联合类型?

Har*_*til 7 javascript rxjs typescript redux redux-observable

Typescript支持有区别的联盟.在下面的示例中,如何将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')
);
Run Code Online (Sandbox Code Playgroud)

我上面的代码片段,我想看到newObs $将其类型推断为:Observable<Square>.但显然,TypeScript不这样做.

怎么做到这一点?我是否达到了TypeScript类型推断的极限?

我寻找这个,因为它似乎在Redux + Redux-Observable代码库中非常有用.

mar*_*tin 8

实际上你可以使用 TypeScript 类型保护来做到这一点。请参阅http://www.typescriptlang.org/docs/handbook/advanced-types.html上的“类型保护和区分类型”部分

这里的关键是function isWhatever(x: any): x is Whatever => ...语法。

这基本上是说,如果isWhatever函数返回true,那么它保证它xWhatever类型。

在您的示例中,TypeScript 考虑所有三个类:

无类型保护

因此,您可以将谓词函数定义为filter()

filter((x: Shape): x is Square => x.kind === 'square')
Run Code Online (Sandbox Code Playgroud)

现在它会正确地只考虑Square类:

带类型保护

查看现场演示:https://stackblitz.com/edit/rxjs6-demo-z9lwxe ?file=index.ts

非常相似的问题:https ://github.com/ReactiveX/rxjs/issues/2340