Tengo un cheque que necesita combinar 2 cheques:
¿Hay una forma más elegante de envolver un valor en un observable solo si aún no es observable? ¿O hay alguna forma de combinar la primera verificación con la segunda cuando la segunda es Observable? ¿O aún refactorizar todo esto de una manera más eficiente?
Por supuesto, este código es un ejemplo para simular lo que obtengo en la aplicación real (ver comentarios en el código).
const getRandomBool: () => boolean = () => Math.random() >= 0.5; const getRandomCheck: () => boolean | Observable<boolean> = () => { return getRandomBool() ? getAsyncCheck() : getSyncCheck(); }; const myFunction = (): Observable<boolean> | boolean => { // First check telling if user is logged, which the UserService returns as Observable<boolean> return of(getRandomBool()) .pipe( mergeMap((isLogged) => { // This is the check which can be either boolean or Observable<boolean> const myCheck = getRandomCheck(); return isLogged ? iif(() => typeof myCheck === 'boolean', of(myCheck), myCheck) : of(!1) }) ) }; ``¿Qué hay de verificar primero si "myCheck" era Observable y usar forkJoin ?
const myFunction: () => Observable<boolean> = () => { let myCheck = getRandomCheck(); myCheck = isObservable(myCheck) ? myCheck : of(myCheck); return forkJoin([of(getRandomBool()), myCheck]) .pipe( map(([logged, yourCheck]) => { return logged ? yourCheck : !1; }) ) } EDITAR Como sugirió BizzyBob, en caso de que myCheck sea asíncrono y tenga un lapso enorme, podría afectar inútilmente toda la ejecución. Entonces podemos usar switchMap para evitar el problema
const myFunction: () => Observable<boolean> = () => { let myCheck = getRandomCheck(); myCheck = isObservable(myCheck) ? myCheck : of(myCheck); return of(getRandomBool()) .pipe( switchMap((logged: boolean) => { return logged ? myCheck : of(!1); }) ) }Ejemplo
const { of, iif, pipe, isObservable , operators: { mergeMap } } = rxjs; const getAsyncCheck = () => of(Boolean(Math.floor(Math.random() * 2))); const getSyncCheck = () => Boolean(Math.floor(Math.random() * 2)); const getRandomBool = () => Boolean(Math.floor(Math.random() * 2)); const getRandomCheck = () => { return getRandomBool() ? getAsyncCheck() : getSyncCheck(); }; const myFunction = () => { return of(getRandomBool()) .pipe( mergeMap((isLogged) => { const myCheck = getRandomCheck(); const result = isLogged ? iif(() => isObservable(myCheck), myCheck, of(myCheck)) : of(false); return result; }) ).subscribe(result => { console.log(result) }) }; myFunction(); <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>Obligaría a randomCheck a observable, luego usaría exhaustMap para manejar la devolución del observable adecuado; cualquiera of(false) cuando, isLogged = false o randomCheck$ lo contrario:
const myFunction = (): Observable<boolean> => { const randomCheck$ = isObservable(randomCheck) ? randomCheck : of(randomCheck); return getIsLogged().pipe( exhaustMap(isLogged => isLogged ? randomCheck$ : of(false)), // take(1) ); }; Si getIsLogged() no se completa, creo que debe usar take(1) para la protección angular.