如何编写接收Observable<T[]>并返回Observable<T>的函数?
解决RxJS中Observable数组转单个Observable对象的类型问题
嘿,我来帮你搞定这个问题!你现在遇到的核心问题是没搞清楚RxJS操作符是怎么处理Observable发出的值的,我给你一步步拆解:
首先看你最初的写法:
getTransaction(id: number): Observable<Transaction>{ return this.getTransactions().pipe(find(txn => txn.id === id)); }
这里的问题是:getTransactions()发出的是整个Transaction[]数组,而RxJS的find操作符是用来寻找流中单个发出的元素是否符合条件的——它会把整个数组当成一个元素来检查,而数组本身没有id属性,所以自然会报类型错误。
再看你后来尝试的subscribe写法:
let transactions : Transaction[] = []; this.getTransactions().subscribe(txns => transactions=txns); return of(transactions.find(txn => txn.id === id));
这是因为Observable是异步的!你调用subscribe后,不会立刻等到请求完成就执行了return of(...),此时transactions还是初始的空数组(甚至可能还没被赋值),所以会出现“transaction未定义”的错误。处理Observable一定要用操作符来串联异步流,不能用同步的方式去拿值。
正确的两种写法
写法一:直接用map操作符处理数组
这种方式最简单直接,利用数组的find方法在map里处理Observable发出的数组:
import { map } from 'rxjs/operators'; getTransaction(id: number): Observable<Transaction | undefined> { return this.getTransactions().pipe( // 对发出的整个数组执行find操作,返回匹配的单个Transaction map(txns => txns.find(txn => txn.id === id)) ); }
如果你确定一定能找到匹配的Transaction,可以用类型断言或者配合first操作符确保返回值非空:
import { map, first } from 'rxjs/operators'; getTransaction(id: number): Observable<Transaction> { return this.getTransactions().pipe( map(txns => txns.filter(txn => txn.id === id)), first(), // 确保取到至少一个元素(如果没找到会抛出错误) map(txn => txn as Transaction) ); }
写法二:把数组拆成单个元素的流再处理
如果后续还需要对单个Transaction做更多RxJS操作,可以用switchMap配合from把数组转换成发出单个元素的Observable,再用RxJS的find操作符:
import { switchMap, find } from 'rxjs/operators'; import { from } from 'rxjs'; getTransaction(id: number): Observable<Transaction> { return this.getTransactions().pipe( // 把数组转换成发出每个Transaction元素的Observable switchMap(txns => from(txns)), // 现在find是RxJS操作符,寻找第一个匹配id的元素 find(txn => txn.id === id) ); }
这样两种写法都能正确返回Observable<Transaction>类型,解决你遇到的类型错误和异步问题~
内容的提问来源于stack exchange,提问作者BobtheMagicMoose
相关产品推荐
相关产品推荐

