diff --git a/spec-dtslint/helpers.ts b/spec-dtslint/helpers.ts
index 1f4feca793..107e0e20b4 100644
--- a/spec-dtslint/helpers.ts
+++ b/spec-dtslint/helpers.ts
@@ -11,13 +11,24 @@ export class H { h = 0; }
export class I { i = 0; }
export class J { j = 0; }
-export const a = of(new A());
-export const b = of(new B());
-export const c = of(new C());
-export const d = of(new D());
-export const e = of(new E());
-export const f = of(new F());
-export const g = of(new G());
-export const h = of(new H());
-export const i = of(new I());
-export const j = of(new J());
+export const a = new A();
+export const b = new B();
+export const c = new C();
+export const d = new D();
+export const e = new E();
+export const f = new F();
+export const g = new G();
+export const h = new H();
+export const i = new I();
+export const j = new J();
+
+export const a$ = of(new A());
+export const b$ = of(new B());
+export const c$ = of(new C());
+export const d$ = of(new D());
+export const e$ = of(new E());
+export const f$ = of(new F());
+export const g$ = of(new G());
+export const h$ = of(new H());
+export const i$ = of(new I());
+export const j$ = of(new J());
diff --git a/spec-dtslint/operators/concatWith-spec.ts b/spec-dtslint/operators/concatWith-spec.ts
new file mode 100644
index 0000000000..9248195e77
--- /dev/null
+++ b/spec-dtslint/operators/concatWith-spec.ts
@@ -0,0 +1,62 @@
+import { of } from 'rxjs';
+import { concatWith } from 'rxjs/operators';
+import { a, b$, c$, d$, e$ } from 'helpers';
+
+it('should support rest params', () => {
+ const arr = [b$, c$];
+ const o = of(a).pipe(concatWith(...arr)); // $ExpectType Observable
+ const o2 = of(a).pipe(concatWith(d$, ...arr, e$)); // $ExpectType Observable
+});
+
+it('should infer correctly', () => {
+ const o = of(1, 2, 3).pipe(concatWith()); // $ExpectType Observable
+});
+
+it('should support one argument', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1))); // $ExpectType Observable
+});
+
+it('should support two arguments', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1), of(2))); // $ExpectType Observable
+});
+
+it('should support three arguments', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1), of(2), of(3))); // $ExpectType Observable
+});
+
+it('should support four arguments', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1), of(2), of(3), of(4))); // $ExpectType Observable
+});
+
+it('should support five arguments', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1), of(2), of(3), of(4), of(5))); // $ExpectType Observable
+});
+
+it('should support six arguments', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1), of(2), of(3), of(4), of(5), of(6))); // $ExpectType Observable
+});
+
+it('should support six or more arguments', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of(1), of(2), of(3), of(4), of(5), of(6), of(7), of(8), of(9))); // $ExpectType Observable
+});
+
+it('should support promises', () => {
+ const o = of(1, 2, 3).pipe(concatWith(Promise.resolve(4))); // $ExpectType Observable
+});
+
+it('should support arrays', () => {
+ const o = of(1, 2, 3).pipe(concatWith([4, 5])); // $ExpectType Observable
+});
+
+it('should support iterables', () => {
+ const o = of(1, 2, 3).pipe(concatWith('foo')); // $ExpectType Observable
+});
+
+it('should infer correctly with multiple types', () => {
+ const o = of(1, 2, 3).pipe(concatWith(of('foo'), Promise.resolve([1]), of(6))); // $ExpectType Observable
+});
+
+it('should enforce types', () => {
+ const o = of(1, 2, 3).pipe(concatWith(5)); // $ExpectError
+ const p = of(1, 2, 3).pipe(concatWith(of(5), 6)); // $ExpectError
+});
diff --git a/spec-dtslint/operators/merge-spec.ts b/spec-dtslint/operators/merge-spec.ts
index acea883581..71bd76ac2a 100644
--- a/spec-dtslint/operators/merge-spec.ts
+++ b/spec-dtslint/operators/merge-spec.ts
@@ -1,81 +1,81 @@
-import { of, asyncScheduler } from 'rxjs';
+import { asyncScheduler } from 'rxjs';
import { merge } from 'rxjs/operators';
-import { A, B, C, D, E, F, G, a, b, c, d, e, f, g } from '../helpers';
+import { a$, b$, c$, d$, e$, f$} from '../helpers';
it('should accept no parameter', () => {
- const res = a.pipe(merge()); // $ExpectType Observable
+ const res = a$.pipe(merge()); // $ExpectType Observable
});
it('should infer correctly with scheduler param', () => {
- const res = a.pipe(merge(asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(asyncScheduler)); // $ExpectType Observable
});
it('should infer correctly with concurrent param', () => {
- const res = a.pipe(merge(3)); // $ExpectType Observable
+ const res = a$.pipe(merge(3)); // $ExpectType Observable
});
it('should infer correctly with concurrent and scheduler param', () => {
- const res = a.pipe(merge(3, asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(3, asyncScheduler)); // $ExpectType Observable
});
it('should infer correctly with 1 Observable param', () => {
- const res = a.pipe(merge(b)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$)); // $ExpectType Observable
});
it('should infer correctly with 2 Observable param', () => {
- const res = a.pipe(merge(b, c)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$)); // $ExpectType Observable
});
it('should infer correctly with 3 Observable param', () => {
- const res = a.pipe(merge(b, c, d)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$)); // $ExpectType Observable
});
it('should infer correctly with 4 Observable param', () => {
- const res = a.pipe(merge(b, c, d, e)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, e$)); // $ExpectType Observable
});
it('should infer correctly with 5 Observable param', () => {
- const res = a.pipe(merge(b, c, d, e, f)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, e$, f$)); // $ExpectType Observable
});
it('should infer correctly with 1 Observable and concurrent param', () => {
- const res = a.pipe(merge(b, 1)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, 1)); // $ExpectType Observable
});
it('should infer correctly with 2 Observable and concurrent param', () => {
- const res = a.pipe(merge(b, c, 1)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, 1)); // $ExpectType Observable
});
it('should infer correctly with 3 Observable and concurrent param', () => {
- const res = a.pipe(merge(b, c, d, 1)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, 1)); // $ExpectType Observable
});
it('should infer correctly with 4 Observable and concurrent param', () => {
- const res = a.pipe(merge(b, c, d, e, 1)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, e$, 1)); // $ExpectType Observable
});
it('should infer correctly with 5 Observable and concurrent param', () => {
- const res = a.pipe(merge(b, c, d, e, f, 1)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, e$, f$, 1)); // $ExpectType Observable
});
it('should infer correctly with 1 Observable, concurrent, and scheduler param', () => {
- const res = a.pipe(merge(b, 1, asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, 1, asyncScheduler)); // $ExpectType Observable
});
it('should infer correctly with 2 Observable, concurrent, and scheduler param', () => {
- const res = a.pipe(merge(b, c, 1, asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, 1, asyncScheduler)); // $ExpectType Observable
});
it('should infer correctly with 3 Observable, concurrent, and scheduler param', () => {
- const res = a.pipe(merge(b, c, d, 1, asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, 1, asyncScheduler)); // $ExpectType Observable
});
it('should infer correctly with 4 Observable, concurrent, and scheduler param', () => {
- const res = a.pipe(merge(b, c, d, e, 1, asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, e$, 1, asyncScheduler)); // $ExpectType Observable
});
it('should infer correctly with 5 Observable, concurrent, and scheduler param', () => {
- const res = a.pipe(merge(b, c, d, e, f, 1, asyncScheduler)); // $ExpectType Observable
+ const res = a$.pipe(merge(b$, c$, d$, e$, f$, 1, asyncScheduler)); // $ExpectType Observable
});
// TODO: Fix this when the both merge operator and merge creator function has been fix
diff --git a/spec/helpers/test-helper.ts b/spec/helpers/test-helper.ts
index 5043bf7d18..b2d832937d 100644
--- a/spec/helpers/test-helper.ts
+++ b/spec/helpers/test-helper.ts
@@ -5,6 +5,7 @@ import { root } from 'rxjs/internal/util/root';
import { observable } from 'rxjs/internal/symbol/observable';
import { iterator } from 'rxjs/internal/symbol/iterator';
import * as sinon from 'sinon';
+import { expect } from 'chai';
export function lowerCaseO(...args: Array): Observable {
const o = {
@@ -47,6 +48,21 @@ export const createObservableInputs = (value: T) => of(
} as any
) as Observable>;
+/**
+ * Used to signify no subscriptions took place to `expectSubscriptions` assertions.
+ */
+export const NO_SUBS: string[] = [];
+
+/**
+ * Does a deep equality assertion. Used to set up {@link TestScheduler}, so that
+ * trees of marbles can be compared.
+ * @param actual The value to run the expectation against.
+ * @param expected The value expected.
+ */
+export function assertDeepEquals (actual: any, expected: any) {
+ expect(actual).to.deep.equal(expected);
+}
+
global.__root__ = root;
let _raf: any;
diff --git a/spec/operators/concatWith-spec.ts b/spec/operators/concatWith-spec.ts
new file mode 100644
index 0000000000..918754ef08
--- /dev/null
+++ b/spec/operators/concatWith-spec.ts
@@ -0,0 +1,341 @@
+import { expect } from 'chai';
+import { of, Observable } from 'rxjs';
+import { concatWith, mergeMap } from 'rxjs/operators';
+import { TestScheduler } from 'rxjs/testing';
+import { assertDeepEquals, NO_SUBS } from 'spec/helpers/test-helper';
+
+/** @test {concat} */
+describe('concat operator', () => {
+ let rxTest: TestScheduler;
+
+ beforeEach(() => {
+ rxTest = new TestScheduler(assertDeepEquals);
+ });
+
+ it('should concatenate two cold observables', () => {
+ rxTest.run(({ cold, expectObservable }) => {
+ const e1 = cold(' --a--b-|');
+ const e2 = cold(' --x---y--|');
+ const expected = '--a--b---x---y--|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ });
+ });
+
+ it('should work properly with scalar observables', done => {
+ const results: string[] = [];
+
+ const s1 = new Observable(observer => {
+ setTimeout(() => {
+ observer.next(1);
+ observer.complete();
+ });
+ }).pipe(concatWith(of(2)));
+
+ s1.subscribe(
+ x => {
+ results.push('Next: ' + x);
+ },
+ x => {
+ done(new Error('should not be called'));
+ },
+ () => {
+ results.push('Completed');
+ expect(results).to.deep.equal(['Next: 1', 'Next: 2', 'Completed']);
+ done();
+ }
+ );
+ });
+
+ it('should complete without emit if both sources are empty', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --|');
+ const e1subs = ' ^-!';
+ const e2 = cold(' ----|');
+ const e2subs = ' --^---!';
+ const expected = '------|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should not complete if first source does not completes', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---');
+ const e1subs = ' ^--';
+ const e2 = cold(' --|');
+ const e2subs = NO_SUBS;
+ const expected = '---';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should not complete if second source does not completes', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --|');
+ const e1subs = ' ^-!';
+ const e2 = cold(' ---');
+ const e2subs = ' --^--';
+ const expected = '-----';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should not complete if both sources do not complete', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---');
+ const e1subs = ' ^--';
+ const e2 = cold(' ---');
+ const e2subs = NO_SUBS;
+ const expected = '---';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should raise error when first source is empty, second source raises error', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --|');
+ const e1subs = ' ^-!';
+ const e2 = cold(' ----#');
+ const e2subs = ' --^---!';
+ const expected = '------#';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should raise error when first source raises error, second source is empty', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---#');
+ const e1subs = ' ^--!';
+ const e2 = cold(' ----|');
+ const expected = '---#';
+ const e2subs = NO_SUBS;
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should raise first error when both source raise error', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---#');
+ const e1subs = ' ^--!';
+ const e2 = cold(' ------#');
+ const expected = '---#';
+ const e2subs = NO_SUBS;
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should concat if first source emits once, second source is empty', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --a--|');
+ const e1subs = ' ^----!';
+ const e2 = cold(' --------|');
+ const e2subs = ' -----^-------!';
+ const expected = '--a----------|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should concat if first source is empty, second source emits once', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --|');
+ const e1subs = ' ^-!';
+ const e2 = cold(' --a--|');
+ const e2subs = ' --^----!';
+ const expected = '----a--|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should emit element from first source, and should not complete if second ' + 'source does not completes', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --a--|');
+ const e1subs = ' ^----!';
+ const e2 = cold(' ---');
+ const e2subs = ' -----^--';
+ const expected = '--a-----';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should not complete if first source does not complete', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---');
+ const e1subs = ' ^--';
+ const e2 = cold(' --a--|');
+ const e2subs = NO_SUBS;
+ const expected = '---';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should emit elements from each source when source emit once', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---a|');
+ const e1subs = ' ^---!';
+ const e2 = cold(' -----b--|');
+ const e2subs = ' ----^-------!';
+ const expected = '---a-----b--|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should unsubscribe to inner source if outer is unsubscribed early', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---a-a--a| ');
+ const e1subs = ' ^--------! ';
+ const e2 = cold(' -----b-b--b-|');
+ const e2subs = ' ---------^-------!';
+ const unsub = ' -----------------! ';
+ const expected = ' ---a-a--a-----b-b ';
+
+ expectObservable(e1.pipe(concatWith(e2)), unsub).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should not break unsubscription chains when result is unsubscribed explicitly', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---a-a--a| ');
+ const e1subs = ' ^--------! ';
+ const e2 = cold(' -----b-b--b-|');
+ const e2subs = ' ---------^--------! ';
+ const expected = '---a-a--a-----b-b- ';
+ const unsub = ' ------------------! ';
+
+ const result = e1.pipe(
+ mergeMap(x => of(x)),
+ concatWith(e2),
+ mergeMap(x => of(x))
+ );
+
+ expectObservable(result, unsub).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should raise error from first source and does not emit from second source', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --#');
+ const e1subs = ' ^-!';
+ const e2 = cold(' ----a--|');
+ const e2subs = NO_SUBS;
+ const expected = '--#';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should emit element from first source then raise error from second source', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' --a--|');
+ const e1subs = ' ^----!';
+ const e2 = cold(' -------#');
+ const e2subs = ' -----^------!';
+ const expected = '--a---------#';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it(
+ 'should emit all elements from both hot observable sources if first source ' +
+ 'completes before second source starts emit',
+ () => {
+ rxTest.run(({ hot, expectObservable, expectSubscriptions }) => {
+ const e1 = hot(' --a--b-|');
+ const e1subs = ' ^------!';
+ const e2 = hot(' --------x--y--|');
+ const e2subs = ' -------^------!';
+ const expected = '--a--b--x--y--|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ }
+ );
+
+ it(
+ 'should emit elements from second source regardless of completion time ' + 'when second source is cold observable',
+ () => {
+ rxTest.run(({ hot, cold, expectObservable, expectSubscriptions }) => {
+ const e1 = hot(' --a--b--c---|');
+ const e1subs = ' ^-----------!';
+ const e2 = cold(' -x-y-z-|');
+ const e2subs = ' ------------^------!';
+ const expected = '--a--b--c----x-y-z-|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ }
+ );
+
+ it('should not emit collapsing element from second source', () => {
+ rxTest.run(({ hot, expectObservable, expectSubscriptions }) => {
+ const e1 = hot(' --a--b--c--|');
+ const e1subs = ' ^----------!';
+ const e2 = hot(' --------x--y--z--|');
+ const e2subs = ' -----------^-----!';
+ const expected = '--a--b--c--y--z--|';
+
+ expectObservable(e1.pipe(concatWith(e2))).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ expectSubscriptions(e2.subscriptions).toBe(e2subs);
+ });
+ });
+
+ it('should emit self without parameters', () => {
+ rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
+ const e1 = cold(' ---a-|');
+ const e1subs = ' ^----!';
+ const expected = '---a-|';
+
+ expectObservable(e1.pipe(concatWith())).toBe(expected);
+ expectSubscriptions(e1.subscriptions).toBe(e1subs);
+ });
+ });
+});
diff --git a/src/internal/operators/concat.ts b/src/internal/operators/concat.ts
index 46871cccee..42f86abb76 100644
--- a/src/internal/operators/concat.ts
+++ b/src/internal/operators/concat.ts
@@ -3,26 +3,26 @@ import { Observable } from '../Observable';
import { ObservableInput, OperatorFunction, MonoTypeOperatorFunction, SchedulerLike } from '../types';
/* tslint:disable:max-line-length */
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(scheduler?: SchedulerLike): MonoTypeOperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(v2: ObservableInput, scheduler?: SchedulerLike): OperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(v2: ObservableInput, v3: ObservableInput, scheduler?: SchedulerLike): OperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, scheduler?: SchedulerLike): OperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, scheduler?: SchedulerLike): OperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, v6: ObservableInput, scheduler?: SchedulerLike): OperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(...observables: Array | SchedulerLike>): MonoTypeOperatorFunction;
-/** @deprecated Deprecated in favor of static concat. */
+/** @deprecated remove in v8. Use {@link concatWith} */
export function concat(...observables: Array | SchedulerLike>): OperatorFunction;
/* tslint:enable:max-line-length */
/**
- * @deprecated Deprecated in favor of static {@link concat}.
+ * @deprecated remove in v8. Use {@link concatWith}
*/
export function concat(...observables: Array | SchedulerLike>): OperatorFunction {
return (source: Observable) => source.lift.call(concatStatic(source, ...(observables as any[])));
diff --git a/src/internal/operators/concatWith.ts b/src/internal/operators/concatWith.ts
new file mode 100644
index 0000000000..a67c827af7
--- /dev/null
+++ b/src/internal/operators/concatWith.ts
@@ -0,0 +1,48 @@
+import { concat as concatStatic } from '../observable/concat';
+import { Observable } from '../Observable';
+import { ObservableInput, OperatorFunction, ObservedValuesFromArray } from '../types';
+
+export function concatWith(): OperatorFunction;
+export function concatWith[]>(...otherSources: A): OperatorFunction | T>;
+
+/**
+ * Emits all of the values from the source observable, then, once it completes, subscribes
+ * to each observable source provided, one at a time, emitting all of their values, and not subscribing
+ * to the next one until it completes.
+ *
+ * `concat(a$, b$, c$)` is the same as `a$.pipe(concatWith(b$, c$))`.
+ *
+ * ## Example
+ *
+ * Listen for one mouse click, then listen for all mouse moves.
+ *
+ * ```ts
+ * import { fromEvent } from 'rxjs';
+ * import { concatWith } from 'rxjs/operators';
+ *
+ * const clicks$ = fromEvent(document, 'click');
+ * const moves$ = fromEvent(document, 'mousemove');
+ *
+ * clicks$.pipe(
+ * map(() => 'click'),
+ * take(1),
+ * concatWith(
+ * moves$.pipe(
+ * map(() => 'move')
+ * )
+ * )
+ * )
+ * .subscribe(x => console.log(x));
+ *
+ * // 'click'
+ * // 'move'
+ * // 'move'
+ * // 'move'
+ * // ...
+ * ```
+ *
+ * @param otherSources Other observable sources to subscribe to, in sequence, after the original source is complete.
+ */
+export function concatWith[]>(...otherSources: A): OperatorFunction | T> {
+ return (source: Observable) => source.lift.call(concatStatic(source, ...otherSources));
+}
diff --git a/src/operators/index.ts b/src/operators/index.ts
index 53b8e697b4..80a311fe10 100644
--- a/src/operators/index.ts
+++ b/src/operators/index.ts
@@ -14,6 +14,7 @@ export { concat } from '../internal/operators/concat';
export { concatAll } from '../internal/operators/concatAll';
export { concatMap } from '../internal/operators/concatMap';
export { concatMapTo } from '../internal/operators/concatMapTo';
+export { concatWith } from '../internal/operators/concatWith';
export { count } from '../internal/operators/count';
export { debounce } from '../internal/operators/debounce';
export { debounceTime } from '../internal/operators/debounceTime';