从 RxJS Observable 中过滤 undefined

dje*_*lin 13 rxjs typescript

是否有特定的习惯用法或实用程序用于undefined从 RxJS observables 中过滤?此代码具有我想要的行为:

obs.pipe(filter(x => x !== undefined))
Run Code Online (Sandbox Code Playgroud)

一些替代方案是

obs.pipe(filter(x => x)) // for all falsy values

obs.pipe(filter(Boolean)) // for falsy variables using Boolean ctor
Run Code Online (Sandbox Code Playgroud)

小智 20

严格来说,单独使用过滤器来删除未定义的值并不能满足您的所有需求。它过滤掉未定义的值,但不会更改类型以指示未定义不再是可能的值。

在示例中:

const obs = new Subject<string | undefined>;
const stringObs = obs.pipe(filter(x => x !== undefined))
Run Code Online (Sandbox Code Playgroud)

stringObs观察到的仍然有型Observable<string | undefined>

要解决此问题,您需要使用:

const stringObs = obs.pipe(filter(x => x !== undefined) as OperatorFunction<string | undefined, string>)
Run Code Online (Sandbox Code Playgroud)

如果您使用严格的空检查,这只是一个真正的问题,但是如果您这样做(并且可以说您应该这样做),那么创建自定义运算符突然变得更有意义!就像是

function filterNullish<T>(): UnaryFunction<Observable<T | null | undefined>, Observable<T>> {
  return pipe(
    filter(x => x != null) as OperatorFunction<T | null |  undefined, T>
  );
}
Run Code Online (Sandbox Code Playgroud)

做这项工作。

然后您可以使用:

const stringObs = obs.pipe(filterNullish())
Run Code Online (Sandbox Code Playgroud)

stringObswill的类型Observable<string>。Typescript 能够T正确推断出类型给我留下了深刻的印象。

  • 这个答案很棒,您提出了一个简单的问题,并且通过应用真实的经验来解决微妙的打字问题,超出了所要求的范围!我唯一的小问题是你的代码片段依赖于 `filter(x =&gt; x != null)` 的松散相等性检查,因为我想确保使用严格的相等性检查,所以我想我会使用 `filter( x =&gt; !!x)` 或 `filter(x =&gt; Boolean(t))` 代替。 (6认同)

pie*_*dar 6

为了帮助打字稿理解未定义的值已被删除,一种方法是创建一个自定义 operator。另一种方法是通过用户定义的类型保护

function isDefined<T>(arg: T | null | undefined): arg is T {
  return arg !== null && arg !== undefined;
}

const obs = from(['hello', null, undefined]);
const filtered: Observable<string> = obs.pipe(filter(isDefined));
Run Code Online (Sandbox Code Playgroud)

  • 这应该包含在 RxJS 运算符中。 (7认同)
  • @MikkelR.Lund 即使在“T = undefined”时,“extends”部分也可以使其工作。否则编译器会认为“isDefined(undefined)”证明了“arg is undefined”,这是不正确的。 (2认同)

dud*_*wad 4

Rxjs 运算符被认为是低级的,旨在以可读的方式组合以创建可预测使用的结果可观察值。让一个“实用程序”为你做这件事并不完全是我(谦虚地)所说的“rxjs 方式”。如果您所说的“惯用语”是指约定,那么您的代码示例基本上就是您要寻找的内容。

我自己定期使用精确的过滤器模式,以至于我考虑过创建一个自定义运算符;然而,而不是这个:

obs.pipe(filter(x => x !== undefined))
Run Code Online (Sandbox Code Playgroud)

你最终会得到这样的结果:

obs.pipe(notUndefined()) // or hasValue() or whatever you want to name it...
Run Code Online (Sandbox Code Playgroud)

这里没有太多积蓄。我认为你甚至没有在可读性上得到节省(或者说完全是边缘性的),这就是为什么我从来没有抽出时间来考虑它。不对此进行动员的另一个理由是,过滤布尔值也很常见,这会让您开始怀疑是否应该将两者结合起来,以避免出现太多令人困惑/类似的运算符,所有这些都可以轻松创建filter无论如何使用等等等等......

长话短说,我对这个确切的问题思考了很多,并且认为您只需使用您提供的代码示例即可。这是正确的”。它是“rx-js-y”。它是可读的。