Angular 2 & Typescript Observable Function Parameter - What Does Pipe Do?

3.5k views Asked by At

Recently I had a need to take an Observer parameter in a function, and I was banging my head on my desk trying to figure out how to do this in Typescript. You might recall taking a delegate parameter in C#; that's basically what I was trying to do here. This was part of a subscribe(observer: Observer<any>). The reason I was doing this is because I was trying to add an AOP type of bookend for subscriptions. That's not the important part.

Basically to get this to work, you have to add a | character behind your function parameter, and it ends up like this:

(observer: Observer<any> | ((value: any) => void)): void

My question basically is what does the bold part do in that function signature? I've scoured every resource I can think of but can't figure it out. Without the portion after the |, I was getting this error:

Argument of type '(res: any) => void' is not assignable to parameter of type 'Observer'. Property 'next' is missing in type '(res: any) => void'.

Once I added the pipe character and portion after, I was able to subscribe without issue in the traditional observer way (using an arrow function), and I have also confirmed that all subscriptions work (which rules out the portion after the pipe being a default value). Any ideas would be appreciated, because I hate seeing something work but having no idea why!

2

There are 2 answers

3
eko On BEST ANSWER

It means the observer is of type Observer<any>

|(or)

((value: any) => void) : A function whose input is any value and output is void.

1
Dan On

as @echonax said: it means OR as @Rob said its a Union Type

but I started writing this and I dont feel like throwing it away :), just because I'm slow. :)

1st you restricted yuor method to accept Observers

class SubscribeMe<T> {
    observable: Observable<T>;
    susbscribe(observer: Observer<T>){
        return observable.susbscribe(observer);
    }
}

then you tried to invoke it with an Action like signature where Action is like

    type Action = <T>(t:T)=> void     

by doing :

    susbscribeMe = new SubscribeMe<any>();
    susbscribeMe.susbscribe((x)=> console.log(x));

That doesn't match signature previously provided.

Then you added Action like signature to the method

 class SubscribeMe<T> {
    observabel: Observable<T>
    susbscribe(observer: Observer<T>| (x)=> void ){
        return observable.susbscribe(observer);
    }
}    

or...

 class SubscribeMe<T> {
    observabel: Observable<T>
    susbscribe(observer: Observer<T>| Action<T>){
        return observable.susbscribe(observer);
    }
}

With that You told typescript you can call me with an Action Or With an Observer

... and finally this is all posible becasue Rx.Observable interface (rxjs/Observable.d.ts)

defines an overloaded signature for "subscribe" like the following

 *  subscribe(): Subscription;
 *  subscribe(observer: PartialObserver<T>): Subscription;
 *  subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;

Which means you can subscribe with

  • OR an Action
  • OR an Observer
  • Or Null/Nothing/Nada

but will always return a Subscription

ex:

import * as Rx from "rxjs";

export class SubscribeMe<T> {

    private _events = new Rx.Subject<T>();

    /** 
    * Hide the source of the observable  
    * */
    get events(): Rx.Observable<T> { return this._events.asObservable(); }

    /**
    *  Accept any signature accepted by Rx.Observabe INTERFACE (rxjs/Observable.d.ts)
    *  subscribe(): Subscription;
    *  subscribe(observer: PartialObserver<T>): Subscription;
    *  subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
    * 
    * as in OR Action<Ievent> Or Observer<Ievent> Or Null/Nothing/Nada
    */
    subscribe = (observer?: (e:T) => void | Rx.Observer<T>) => {
        return this.events.subscribe(observer);
    }
}