JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.0-beta.11/Rx.umd.min.js"></script>

Babel + JSX

const users = [
    { name: "A", type: 2, level: 1 },
    { name: "B", type: 1, level: 2 }
];
const types = [
    { description: "Type 1", id: 1 },
    { description: "Type 2", id: 2 }
];
const levels = [
    { description: "Level 1", id: 1 },
    { description: "Level 2", id: 2 }
];

const users$ = Rx.Observable.from(users);
const types$ = Rx.Observable.from(types);
const levels$ = Rx.Observable.from(levels);

function join(s$, sourceProperty, targetProperty, streamProperty) {
	return function(initObj) {
  	const stream$ = s$.filter(x => x.id === initObj[sourceProperty]);
  	return Rx.Observable.combineLatest(
    	Rx.Observable.of(initObj),
      stream$,
      (obj, streamObj) => {
      	const prop = streamObj[streamProperty];
      	return Object.assign({}, obj, { [targetProperty]: prop });
      } 
    );
  };
}

users$
	.switchMap(join(types$, 'type', 'typeDescription', 'description'))
  .switchMap(join(levels$, 'level', 'levelDescription', 'description'))
  .subscribe(x => console.log(x));