Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions spec/exports-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { from } from '../src/internal/observable/from';
import { fromEvent } from '../src/internal/observable/fromEvent';
import { fromEventPattern } from '../src/internal/observable/fromEventPattern';
import { fromPromise } from '../src/internal/observable/fromPromise';
import { _if } from '../src/internal/observable/if';
import { iif } from '../src/internal/observable/iif';
import { interval } from '../src/internal/observable/interval';
import { merge } from '../src/internal/observable/merge';
import { never } from '../src/internal/observable/never';
Expand Down Expand Up @@ -70,8 +70,8 @@ describe('exports', () => {
expect(fromPromise).to.equal(Rx.Observable.fromPromise);
});

it('should have rxjs/observable/if', () => {
expect(_if).to.equal(Rx.Observable.if);
it('should have rxjs/observable/iif', () => {
expect(iif).to.equal(Rx.Observable.if);
});

it('should have rxjs/observable/interval', () => {
Expand Down
28 changes: 13 additions & 15 deletions spec/observables/if-spec.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import { expect } from 'chai';
import * as Rx from '../../src/Rx';
import { iif, of } from '../../src';
import { expectObservable } from '../helpers/marble-testing';

const Observable = Rx.Observable;

describe('Observable.if', () => {
describe('iif', () => {
it('should subscribe to thenSource when the conditional returns true', () => {
const e1 = Observable.if(() => true, Observable.of('a'));
const e1 = iif(() => true, of('a'));
const expected = '(a|)';

expectObservable(e1).toBe(expected);
});

it('should subscribe to elseSource when the conditional returns false', () => {
const e1 = Observable.if(() => false, Observable.of('a'), Observable.of('b'));
const e1 = iif(() => false, of('a'), of('b'));
const expected = '(b|)';

expectObservable(e1).toBe(expected);
});

it('should complete without an elseSource when the conditional returns false', () => {
const e1 = Observable.if(() => false, Observable.of('a'));
const e1 = iif(() => false, of('a'));
const expected = '|';

expectObservable(e1).toBe(expected);
});

it('should raise error when conditional throws', () => {
const e1 = Observable.if(<any>(() => {
const e1 = iif(<any>(() => {
throw 'error';
}), Observable.of('a'));
}), of('a'));

const expected = '#';

Expand All @@ -38,7 +36,7 @@ describe('Observable.if', () => {

it('should accept resolved promise as thenSource', (done: MochaDone) => {
const expected = 42;
const e1 = Observable.if(() => true, new Promise((resolve: any) => { resolve(expected); }));
const e1 = iif(() => true, new Promise((resolve: any) => { resolve(expected); }));

e1.subscribe(x => {
expect(x).to.equal(expected);
Expand All @@ -51,8 +49,8 @@ describe('Observable.if', () => {

it('should accept resolved promise as elseSource', (done: MochaDone) => {
const expected = 42;
const e1 = Observable.if(() => false,
Observable.of('a'),
const e1 = iif(() => false,
of('a'),
new Promise((resolve: any) => { resolve(expected); }));

e1.subscribe(x => {
Expand All @@ -66,8 +64,8 @@ describe('Observable.if', () => {

it('should accept rejected promise as elseSource', (done: MochaDone) => {
const expected = 42;
const e1 = Observable.if(() => false,
Observable.of('a'),
const e1 = iif(() => false,
of('a'),
new Promise((resolve: any, reject: any) => { reject(expected); }));

e1.subscribe(x => {
Expand All @@ -82,7 +80,7 @@ describe('Observable.if', () => {

it('should accept rejected promise as thenSource', (done: MochaDone) => {
const expected = 42;
const e1 = Observable.if(() => true, new Promise((resolve: any, reject: any) => { reject(expected); }));
const e1 = iif(() => true, new Promise((resolve: any, reject: any) => { reject(expected); }));

e1.subscribe(x => {
done(new Error('should not be called'));
Expand Down
5 changes: 3 additions & 2 deletions src/add/observable/if.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Observable } from '../../internal/Observable';
import { _if } from '../../internal/observable/if';
import { iif } from '../../internal/observable/iif';

Observable.if = _if;
//tslint:disable-next-line:no-any TypeScript doesn't like `if`
(Observable as any).if = iif;
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export { from } from './internal/observable/from';
export { fromEvent } from './internal/observable/fromEvent';
export { fromEventPattern } from './internal/observable/fromEventPattern';
export { generate } from './internal/observable/generate';
export { _if as iif } from './internal/observable/if';
export { iif } from './internal/observable/iif';
export { interval } from './internal/observable/interval';
export { merge } from './internal/observable/merge';
export { never } from './internal/observable/never';
Expand Down
5 changes: 3 additions & 2 deletions src/internal/Observable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Subscription } from './Subscription';
import { TeardownLogic } from './types';
import { root } from './util/root';
import { toSubscriber } from './util/toSubscriber';
import { IfObservable } from './observable/IfObservable';
import { iif } from './observable/iif';
import { observable as Symbol_observable } from '../internal/symbol/observable';
import { OperatorFunction, PartialObserver, Subscribable } from '../internal/types';
import { pipeFromArray } from './util/pipe';
Expand Down Expand Up @@ -248,8 +248,9 @@ export class Observable<T> implements Subscribable<T> {
return this.source.subscribe(subscriber);
}

// TODO(benlesh): determine if this is still necessary
// `if` and `throw` are special snow flakes, the compiler sees them as reserved words
static if: typeof IfObservable.create;
static if: typeof iif;

/**
* An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable
Expand Down
140 changes: 0 additions & 140 deletions src/internal/observable/IfObservable.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/internal/observable/if.ts

This file was deleted.

93 changes: 93 additions & 0 deletions src/internal/observable/iif.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Observable } from '../Observable';
import { defer } from './defer';
import { EMPTY } from './empty';
import { SubscribableOrPromise } from '../types';

/**
* Decides at subscription time which Observable will actually be subscribed.
*
* <span class="informal">`If` statement for Observables.</span>
*
* `if` accepts a condition function and two Observables. When
* an Observable returned by the operator is subscribed, condition function will be called.
* Based on what boolean it returns at that moment, consumer will subscribe either to
* the first Observable (if condition was true) or to the second (if condition was false). Condition
* function may also not return anything - in that case condition will be evaluated as false and
* second Observable will be subscribed.
*
* Note that Observables for both cases (true and false) are optional. If condition points to an Observable that
* was left undefined, resulting stream will simply complete immediately. That allows you to, rather
* then controlling which Observable will be subscribed, decide at runtime if consumer should have access
* to given Observable or not.
*
* If you have more complex logic that requires decision between more than two Observables, {@link defer}
* will probably be a better choice. Actually `if` can be easily implemented with {@link defer}
* and exists only for convenience and readability reasons.
*
*
* @example <caption>Change at runtime which Observable will be subscribed</caption>
* let subscribeToFirst;
* const firstOrSecond = Rx.Observable.if(
* () => subscribeToFirst,
* Rx.Observable.of('first'),
* Rx.Observable.of('second')
* );
*
* subscribeToFirst = true;
* firstOrSecond.subscribe(value => console.log(value));
*
* // Logs:
* // "first"
*
* subscribeToFirst = false;
* firstOrSecond.subscribe(value => console.log(value));
*
* // Logs:
* // "second"
*
*
* @example <caption>Control an access to an Observable</caption>
* let accessGranted;
* const observableIfYouHaveAccess = Rx.Observable.if(
* () => accessGranted,
* Rx.Observable.of('It seems you have an access...') // Note that only one Observable is passed to the operator.
* );
*
* accessGranted = true;
* observableIfYouHaveAccess.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('The end')
* );
*
* // Logs:
* // "It seems you have an access..."
* // "The end"
*
* accessGranted = false;
* observableIfYouHaveAccess.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('The end')
* );
*
* // Logs:
* // "The end"
*
* @see {@link defer}
*
* @param {function(): boolean} condition Condition which Observable should be chosen.
* @param {Observable} [trueObservable] An Observable that will be subscribed if condition is true.
* @param {Observable} [falseObservable] An Observable that will be subscribed if condition is false.
* @return {Observable} Either first or second Observable, depending on condition.
* @static true
* @name iif
* @owner Observable
*/
export function iif<T, F>(
condition: () => boolean,
trueResult: SubscribableOrPromise<T> = EMPTY,
falseResult: SubscribableOrPromise<F> = EMPTY
): Observable<T|F> {
return defer<T|F>(() => condition() ? trueResult : falseResult);
}