如何从已有Observable创建新Observable?RxJS代码实现疑问
Hey there! Let's fix up that usedRoles observable you're working on. The key here is mixing RxJS operators with array methods correctly—let's break it down step by step.
The Core Problem
Your users observable emits an array of User objects, each with their own roles: Role[] array. You want to take all those role arrays, flatten them into a single list of roles, and wrap that in an Observable<Role[]>.
The Correct Implementation
Here's how to write it properly:
import { map } from 'rxjs/operators'; public get usedRoles(): Observable<Role[]> { return this.users.pipe( // Take the emitted User[] and flatten all their roles into a single Role[] map(users => users.flatMap(user => user.roles)) ); }
If you're using an older RxJS version that uses chained operators instead of pipe(), it looks like this:
public get usedRoles(): Observable<Role[]> { return this.users.map(users => users.flatMap(user => user.roles)); }
Why Your Initial Approach Was Off
You tried using RxJS's flatMap (now called mergeMap), but that's for flattening streams of observables/promises/arrays into a single stream of values. If you'd continued with flatMap, you'd end up with an Observable<Role> (emitting individual role objects one by one) instead of an Observable<Role[]> (emitting a single array of all roles).
Instead, we use RxJS's map operator to transform the emitted User[] directly into a Role[], and use the array's flatMap method (not RxJS's) to flatten the nested Role[][] into a single Role[].
Bonus: Deduplicate Roles (If Needed)
If you want to avoid duplicate roles (since multiple users might share the same role), you can add deduplication logic. For example, if your Role has an id property:
public get usedRoles(): Observable<Role[]> { return this.users.pipe( map(users => { const seenRoleIds = new Set<number>(); return users.flatMap(user => user.roles).filter(role => { if (!seenRoleIds.has(role.id)) { seenRoleIds.add(role.id); return true; } return false; }); }) ); }
Or if you just want to deduplicate based on object references (works if roles are singletons):
map(users => [...new Set(users.flatMap(user => user.roles))])
内容的提问来源于stack exchange,提问作者Anand

