Skip to content

Commit

Permalink
fix(takeLast): add runtime assertions for invalid arguments
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Calling takeLast without arguments or with an argument that is NaN will throw a TypeError
  • Loading branch information
benlesh committed Feb 26, 2020
1 parent 1dca98a commit 6828bb5
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 14 deletions.
14 changes: 14 additions & 0 deletions spec/operators/takeLast-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ describe('takeLast operator', () => {
rxTest = new TestScheduler(assertDeepEquals);
});

it('should error for invalid arguments', () => {
expect(() => {
of(1, 2, 3).pipe((takeLast as any)());
}).to.throw(TypeError, `'count' is not a number`);

expect(() => {
of(1, 2, 3).pipe((takeLast as any)('banana'));
}).to.throw(TypeError, `'count' is not a number`);

expect(() => {
of(1, 2, 3).pipe((takeLast as any)('3'));
}).not.to.throw();
});

it('should take two values of an observable with many values', () => {
rxTest.run(({ cold, expectObservable, expectSubscriptions }) => {
const e1 = cold('--a-----b----c---d--| ');
Expand Down
26 changes: 12 additions & 14 deletions src/internal/operators/takeLast.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Operator } from '../Operator';
import { Subscriber } from '../Subscriber';
import { ArgumentOutOfRangeError } from '../util/ArgumentOutOfRangeError';
import { empty } from '../observable/empty';
import { EMPTY } from '../observable/empty';
import { Observable } from '../Observable';
import { MonoTypeOperatorFunction, TeardownLogic } from '../types';

Expand Down Expand Up @@ -39,18 +39,24 @@ import { MonoTypeOperatorFunction, TeardownLogic } from '../types';
*
* @throws {ArgumentOutOfRangeError} When using `takeLast(i)`, it delivers an
* ArgumentOutOrRangeError to the Observer's `error` callback if `i < 0`.
* @throws {TypeError} If the count is not provided or is not a number.
*
* @param {number} count The maximum number of values to emit from the end of
* @param count The maximum number of values to emit from the end of
* the sequence of values emitted by the source Observable.
* @return {Observable<T>} An Observable that emits at most the last count
* @return An Observable that emits at most the last count
* values emitted by the source Observable.
* @method takeLast
* @owner Observable
*/
export function takeLast<T>(count: number): MonoTypeOperatorFunction<T> {
if (isNaN(count)) {
throw new TypeError(`'count' is not a number`);
}
if (count < 0) {
throw new ArgumentOutOfRangeError;
}

return function takeLastOperatorFunction(source: Observable<T>): Observable<T> {
if (count === 0) {
return empty();
return EMPTY;
} else {
return source.lift(new TakeLastOperator(count));
}
Expand All @@ -59,21 +65,13 @@ export function takeLast<T>(count: number): MonoTypeOperatorFunction<T> {

class TakeLastOperator<T> implements Operator<T, T> {
constructor(private total: number) {
if (this.total < 0) {
throw new ArgumentOutOfRangeError;
}
}

call(subscriber: Subscriber<T>, source: any): TeardownLogic {
return source.subscribe(new TakeLastSubscriber(subscriber, this.total));
}
}

/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class TakeLastSubscriber<T> extends Subscriber<T> {
private ring: Array<T> = new Array();
private count: number = 0;
Expand Down

0 comments on commit 6828bb5

Please sign in to comment.