代码之家  ›  专栏  ›  技术社区  ›  Harshal Patil

typescript使用rx.js筛选器运算符区分联合类型?

  •  7
  • Harshal Patil  · 技术社区  · 7 年前

    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 不这样做。

    如何做到这一点?我是否达到了打字稿类型推理的极限?

    我在找这个,因为它在 Redux + Redux-Observable 代码库。

    2 回复  |  直到 7 年前
        1
  •  4
  •   martin    7 年前

    实际上,您可以使用类型脚本类型的保护来执行此操作。参见“类型保护和区分类型”一节 http://www.typescriptlang.org/docs/handbook/advanced-types.html

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

    这基本上说如果 isWhatever 函数返回 true 然后它保证 x Whatever 类型。

    在示例中,typescript考虑所有三个类:

    without-typeguard

    因此,可以为定义谓词函数 filter() 如下所示:

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

    现在它只考虑 Square 班级:

    with-typeguard

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

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

        2
  •  0
  •   Scraph    7 年前

    这不一定是对typescript类型系统的限制,而是对 filter . 您可以使用 flatMap :

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