【问题标题】:Filter all 'null' values from an Observable<T>过滤 Observable<T> 中的所有“空”值
【发布时间】:2017-08-19 23:45:45
【问题描述】:

我有一个主题的服务:

@Injectable() export class UserService() {
    private currentUserSubject = new BehaviorSubject<User>(null);
    public currentUser = this.currentUserSubject.asObservable().distinctUntilChanged(); 

    ... // emitting new User    
}

有一个组件我将这个服务注入并订阅更新:

@Component() export class UserComponent {
    constructor(private userService: UserService) {
        this.userService.currentUser
            .subscribe((user) => {
                // I want to see not null value here
            })
    }
}

我想对Observable&lt;User&gt; 应用一些东西来过滤所有空值并仅在实际加载User 时进入订阅。

【问题讨论】:

  • 为什么不在回调中测试它是否为空?或者,有一个Observable.filter
  • 就编写好的代码而言,我认为这不是正确的决定。我想“告诉”我只订阅非空值而不是所有值并在#subscribe 中过滤。

标签: javascript angular typescript rxjs observable


【解决方案1】:

很简单:

filter(user => !!user),

过滤these falsy values (link to Falsy on MDN)。 或者像这样转换为布尔值:

filter(user => Boolean(user)),

如果用户评估为 false,则过滤器不会通过。


更新(在 Mick 对类型检查发表评论之后):

如果你想添加一些更合适的打字稿解决方案,你可以使用类型谓词(用户定义的类型保护)。请参阅有关此 here on https://www.typescriptlang.org/ 的文档。

假设你有一个班级User。 示例:

const isUser = (user: null|User): user is User => {
  // You can use any logic here that returns a boolean to confirm the type.
  return user instanceof User;
}

如果你现在这样做:

filter(user => isUser(user));

Typescript 会理解你在过滤器之后有一个 User 类型的对象。

【讨论】:

  • 问题在于 Typescript 不知道用户现在已明确定义
  • @Mick,您可以为此使用类型谓词。检查文档here。我在答案中添加了一个示例。
  • 我认为你的答案已经过时了。 Amit Portnoy 的一个是 IMO 优越的,因为它在您使用“邪恶”any 时提供了一个泛型类型,并且您的函数只能与 User 类型一起使用。
  • @Mick,当然,只是试图帮助更新。将any 更改为null|User,这更符合问题。很抱歉浪费您的时间。祝你有美好的一天。
【解决方案2】:

rxjs@6 的另一个选项是创建另一个 skipWhile 的包装运算符。

// rxjs.utils.js
export const skipNull = () => <T>(source: Observable <T>): Observable<T> => source.pipe(skipWhile(value => value === null));

用法:

this.observable.pipe(skipNull()).subscribe(...)

【讨论】:

    【解决方案3】:

    检查值是否存在的另一种方法:

    public currentUser = this.currentUserSubject
                             .asObservable()
                             .filter<User>(Boolean)
                             .distinctUntilChanged(); 
    

    【讨论】:

    • 确实更好!
    • 是否有使用布尔类作为过滤参数的文档?
    • @ShacharHar-Shuv 他在这里没有使用new,所以它只是执行类型转换。见这里:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 相当于 !!但在这种情况下,它更具可读性,因为我们不必引入 lambda
    • 你会失去类型接口并且 rxjs 6.5 会抱怨未知类型
    • 修复所有你需要的是例如过滤器(布尔值)
    【解决方案4】:

    使用rxjs@6 和打字稿,推荐(可读/可维护)的方法是定义以下类型保护:

    export function isNonNull<T>(value: T): value is NonNullable<T> {
      return value != null;
    }
    

    并用pipefilter 扩充主题:

    subject.pipe(filter(isNonNull))
    

    【讨论】:

    • 打字稿中的控件不应该是 !== null 吗?
    • NonNullable 类型,指的是 null 或 undefined,而不仅仅是 null。如果您想允许未定义的值(这不是人们通常想要的),您需要将检查替换为 !== null 并将 NonNullable 替换为:type NotNull&lt;T&gt; = T extends null ? never : T;
    • 是的,我最终使用了您的解决方案,唯一让我感到惊讶的是命名(我更喜欢明确地说 NotNullNorUndefined),它处理 null 和 undefined 并被命名为“nonNull”,但这非常适合我想要!
    【解决方案5】:

    将过滤器运算符添加到您的可观察链中。您可以显式过滤空值,或者只检查您的用户是否真实 - 您必须根据需要进行调用。

    仅过滤掉空用户:

    public currentUser = this.currentUserSubject
                             .asObservable()
                             .filter(user => user !== null)
                             .distinctUntilChanged(); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 2019-08-15
      • 2015-04-17
      • 1970-01-01
      相关资源
      最近更新 更多