Типизированное объединение типов Typescript с оператором фильтра Rx.js? - PullRequest
0 голосов
/ 25 мая 2018

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')
);

Я выше фрагмента кода, я хотел бы увидеть newObs $, чтобы его тип выводилсякак: Observable<Square>.Но, очевидно, TypeScript этого не делает.

Как этого добиться?Достигаю ли я границ вывода типа TypeScript?

Я ищу это, поскольку оно кажется очень полезным в Redux + Redux-Observable кодовой базе.

Ответы [ 2 ]

0 голосов
/ 10 июня 2018

Это не обязательно ограничение для системы типов TypeScript, а скорее для реализации filter.Вы можете легко достичь желаемого поведения, используя flatMap:

// Inferred type: Observable<Square>
const newObs$ = obs$.pipe(
  flatMap((x) => x.kind === "square" ? of(x) : empty())
);
0 голосов
/ 25 мая 2018

На самом деле вы можете сделать это с защитой типа TypeScript.См. Раздел «Защита типов и дифференциация типов» по ​​адресу 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

...