rxjs TypeError: this._complete is not a function

Viewed 446

I'm learning to write an rxjs operator, when I write like this:

function map<T, R>(project: (value: T) => R): OperatorFunction<T, R> {
  return function mapOperation(source$: Observable<T>): Observable<R> {
    if (typeof project !== "function") {
      throw new TypeError("argument is not a function...");
    }
    return Observable.create((observer: Observer<R>) => {
      console.log(observer.complete);
      const subscription = source$.subscribe({
        next: value => {
          try {
            observer.next(project(value));
          } catch (e) {
            observer.error(e);
          }
        },
        error: observer.error,
        complete: observer.complete // here
      });
      return () => {
        subscription.unsubscribe();
      };
    });
  };
}

const source$ = of(1, 2, 3);
map((x: number) => x * x)(source$).subscribe(console.log);

it goes wrong:

 this._complete();
           ^
TypeError: this._complete is not a function
    at Object.Subscriber.complete (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Subscriber.ts:126:12)
    at Object.wrappedComplete (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Subscriber.ts:248:54)
    at SafeSubscriber.__tryOrUnsub (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Subscriber.ts:265:10)
    at SafeSubscriber.complete (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Subscriber.ts:251:16)
    at Subscriber._complete (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Subscriber.ts:148:22)
    at Subscriber.complete (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Subscriber.ts:126:12)
    at Observable._subscribe (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/util/subscribeToArray.ts:11:14)
    at Observable._trySubscribe (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Observable.ts:238:19)
    at Observable.subscribe (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/node_modules/rxjs/src/internal/Observable.ts:219:14)
    at Observable._subscribe (/Users/ahabhgk/moby-dick/FE/some-note/deep-in-rxjs/index.ts:10:36)

but when I change complete: observer.complete to complete: () => observer.complete(), it's good

function map<T, R>(project: (value: T) => R): OperatorFunction<T, R> {
  return function mapOperation(source$: Observable<T>): Observable<R> {
    if (typeof project !== "function") {
      throw new TypeError("argument is not a function...");
    }
    return Observable.create((observer: Observer<R>) => {
      console.log(observer.complete);
      const subscription = source$.subscribe({
        next: value => {
          try {
            observer.next(project(value));
          } catch (e) {
            observer.error(e);
          }
        },
        error: observer.error,
        complete: () => observer.complete() // here
      });
      return () => {
        subscription.unsubscribe();
      };
    });
  };
}

const source$ = of(1, 2, 3);
map((x: number) => x * x)(source$).subscribe(console.log);

why there is a difference between complete: observer.complete and complete: () => observer.complete(), they all pass in a function

1 Answers

observer.complete is called in a different scope when you are using your arrow function complete: () => observer.complete() and when using complete: observer.complete.

The observer complete() method calls _complete() internally in the execution scope of the function, this._complete().

In your arrow function this will work since you call the method on the observer object instance, meaning it executes in the correct scope (the scope of the observer) where as it does not work in the other case because it is called in the subscriber scope and there is no _complete method defined in that scope, hence the error is thrown.

You could also do this:

complete: observer.complete.bind(observer),

with the bind method you can bind the complete method to the right scope, the scope of the observer.

Related