【问题标题】:Return forkJoin selectively有选择地返回 forkJoin
【发布时间】:2021-09-14 07:24:22
【问题描述】:

我有一个应用程序应该return menu based on given context

以下是menuAmenuB的来源。

// example of menu derived from given source
  menuA() {
    return [
      {
        a: 'demo1',
        b: 'demo2',
        c: 'demo3'
      },
      {
        e: 'demo4',
        f: 'demo5',
        g: 'demo6'
      }
    ];
  }

  // example of menu fetched from different source eg: db
  async menuB() {
    const ret = [];
    const h = {
      a: 'demo1',
      b: 'demo2',
      c: 'demo3'
    };
    ret.push(h);
    return await ret;
  }

鉴于我对 rxjs 的知识和经验有限,我希望下面的 sn-p 可以接受 stringmenuAmenuB 以返回 observablerequired menu

getMenu$(context: string) {
    return forkJoin(
      {
        menuA: of(this.menuA()),
        menuB: from(this.menuB())
      }
    ).pipe(
      mergeMap((m: any) => {
        return m[context];
      })
    )
  }

以上调用警告如下:

Argument of type 'Observable<unknown>' is not assignable to parameter of type 'OperatorFunction<{ menuA: ({ a: string; b: string; c: string; e?: undefined; f?: undefined; g?: undefined; } | { e: string; f: string; g: string; a?: undefined; b?: undefined; c?: undefined; })[]; menuB: { a: string; b: string; c: string; }[]; }, unknown>'.
  Type 'Observable<unknown>' provides no match for the signature '(source: Observable<{ menuA: ({ a: string; b: string; c: string; e?: undefined; f?: undefined; g?: undefined; } | { e: string; f: string; g: string; a?: undefined; b?: undefined; c?: undefined; })[]; menuB: { a: string; b: string; c: string; }[]; }>): Observable<...>'.ts(2345)
The 'this' context of type 'void' is not assignable to method's 'this' of type 'Observable<any>'.ts(2684)

根据下面的评论,我还添加了使用地图替换mergeMap时的警告消息:

// modified getMenu$:
getMenu$(context: string) {
    return forkJoin(
      {
        menuA: of(this.menuA()),
        menuB: from(this.menuB())
      }
    ).pipe(
      map(m => m[context])
    )
  }

警告信息:

Argument of type 'Observable<unknown>' is not assignable to parameter of type 'OperatorFunction<{ menuA: ({ a: string; b: string; c: string; e?: undefined; f?: undefined; g?: undefined; } | { e: string; f: string; g: string; a?: undefined; b?: undefined; c?: undefined; })[]; menuB: { a: string; b: string; c: string; }[]; }, unknown>'.
  Type 'Observable<unknown>' provides no match for the signature '(source: Observable<{ menuA: ({ a: string; b: string; c: string; e?: undefined; f?: undefined; g?: undefined; } | { e: string; f: string; g: string; a?: undefined; b?: undefined; c?: undefined; })[]; menuB: { a: string; b: string; c: string; }[]; }>): Observable<...>'.ts(2345)
The 'this' context of type 'void' is not assignable to method's 'this' of type 'Observable<unknown>'.ts(2684)

我正在使用angular 12rxjs "~6.6.0"

【问题讨论】:

  • mergeMap 替换为map 运算符以返回正确的菜单。
  • 我不确定return await ret; 应该做什么。 ret 是一个数组,但也许它只是一个简化的例子。
  • 当我使用 map 而不是 mergeMap 时,我收到类似的警告:'Observable' 类型的参数不可分配给'OperatorFunction 类型的参数
  • 返回的 await ret 只是一个简单的 sn-p 表示异步数据源。否则,主要感兴趣的领域是开发通过字符串上下文选择从不同来源(包括 Promise)返回菜单的能力。

标签: javascript angular rxjs


【解决方案1】:

演示:https://stackblitz.com/edit/typescript-ktm2hz?file=index.ts

function menuA() {
      return [
        {
          a: 'demo1',
          b: 'demo2',
          c: 'demo3'
        },
        {
          e: 'demo4',
          f: 'demo5',
          g: 'demo6'
        }
      ];
    }
    
    // example of menu fetched from different source eg: db
    function menuB() {
      return of([
        {
          a: 'demo1',
          b: 'demo2',
          c: 'demo3'
        }
      ]).pipe(delay(500));
    }
    
    function getMenu$(context: string) {
      return forkJoin(of(menuA()), menuB().pipe(first())).pipe(
        map(([menuA, menuB]) => ({ menuA, menuB })),
        map(m => m[context])
      );
    }
    getMenu$('menuA').subscribe(data => {
      console.log(data);
    });
    getMenu$('menuB').subscribe(data => {
      console.log(data);
    });

更新:

您需要声明您的菜单。 我已经为它创建了枚举

使用 Angular 12 的演示: https://stackblitz.com/edit/angular-12-template-wcgohi?file=src/app/app.component.ts

import { Component, OnInit } from '@angular/core';
import { forkJoin, Observable, of } from 'rxjs';
import { first, map, delay } from 'rxjs/operators';

enum Menus {
  menuA = 'menuA',
  menuB = 'menuB'
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  menuA(): { [key: string]: any }[] {
    return [
      {
        a: 'demo1',
        b: 'demo2',
        c: 'demo3'
      },
      {
        e: 'demo4',
        f: 'demo5',
        g: 'demo6'
      }
    ];
  }

  // example of menu fetched from different source eg: db
  menuB(): Observable<{ [key: string]: any }[]> {
    return of([
      {
        a: 'demo1',
        b: 'demo2',
        c: 'demo3'
      }
    ]).pipe(delay(500));
  }

  getMenu$(context: Menus): Observable<{ [key: string]: any }[]> {
    return forkJoin([of(this.menuA()), this.menuB().pipe(first())]).pipe(
      map(([menuA, menuB]) => ({ menuA, menuB })),
      map(m => m[context])
    );
  }
  ngOnInit() {
    this.getMenu$(Menus.menuA).subscribe(data => {
      console.log(data);
    });
    this.getMenu$(Menus.menuB).subscribe(data => {
      console.log(data);
    });
  }
}


【讨论】:

  • 非常感谢。让我在我这边测试并恢复
  • 上述在stackblitz中工作,但在角度为12的vsc中引发警告。第一个警告是在延迟(500)上给出的:“'Observable'类型的参数不可分配给类型的参数'OperatorFunction'..."
  • ...其余的分布在 getMenu$ 周围。包括 forkJoin 的签名,然后在 first() 上,我们有“'Observable' 类型的参数不可分配给 'OperatorFunction' 类型的参数......”
  • ...简而言之,它不能按原样编译。我希望得到关于类型警告的解决方案。如果您有任何建议,请告诉我。
  • 让我测试并恢复
猜你喜欢
  • 1970-01-01
  • 2017-12-09
  • 2018-12-08
  • 1970-01-01
  • 1970-01-01
  • 2017-11-12
  • 2021-12-25
  • 2017-10-18
  • 1970-01-01
相关资源
最近更新 更多