## Chris TrzeÅ›niewski

Developer ðŸ¥‘ Advocate

& Senior Fronend Developer @Scalac

# Custom Operators

## What's an Observable

Â

• Stream
• Promise on steroids
• Function that tie observer to a producer

Â

• filter
• debounce
• throttle

## Operators

• map
• scan (reduce)
• switchMap
• mergeMap

## Operators

• combineLatest
• withLatestFrom
• zip

• timer
• interval
• from / of
• create

## Operators

``````const source\$: Observable<number> = timer(1000);

const result\$: Observable<number> = source\$
.pipe(
filter(v => v % 3 === 1),
map(v => v * 7)
);``````

## Custom operators

• Creating specific operators based on existing ones
• Extract multiple operators
• more meaningful
• reusable
• Create missing pieces ourselves

## Under the hood

• Function
• Taking observable as an argument
• Returns observable
``````type OperatorFunction<T, R> =
(source: Observable<T>)): Observable<R>``````
``````const identity =
(source: Observable<any>) => source``````

## Custom operators

• static operators ie. notNull, isTruthy operator

## Extract most common use cases

``const notNull = filter(v => v !== null)``
``const isTruthy = filter(v => !!v)``

## Custom operators

• parametrised operators ie. `multiply`, `power`

## Extract most common use cases

``````const multiply =
m => map(v => v * m)

const power =
p => map(v => Math.pow(v, p))``````

## Group multiple operators into one

``````const myOperator =
<T,R>(source: Observable<T>) =>
source.pipe(operator1, operator2)``````

## Group multiple operators into one

``````const oddValueTimesSeven =
(num\$: Observable<number>) =>
num\$.pipe(â€¨
filter(v => v % 2 === 1),â€¨
map(v => v * 7),
â€¨)``````

## Group multiple operators into one

``````const extractData =
<T>(response\$: Observable<{data: T, loading: boolean}>)
=> response\$.pipe(
isTruthy,
filter(response => !response.loading),
map(v => v.data),
)``````

## Create from scratch

``````const myOperator =
(source: Observable) =>
new Observable((observer: Subscriber) => {
source.subscribe({â€¨
next(x) {/* â€¦ */ observer.next(â€¦)},â€¨
error(err) {/* â€¦ */ observer.error(â€¦)},â€¨
complete(x) {/* â€¦ */ observer.complete(â€¦)},â€¨
})
})``````

## Create from scratch

``````const customMap = <T, R>(
project: (value: T) => R
) => (source: Observable<T>) =>
new Observable<R>(observer =>
source.subscribe({
next(x) { observer.next(project(x)) },
error(err) { observer.error(err) },
complete() { observer.complete() }
})
)``````

## Create from scratch

``````const customMap = <T, R>(
project: (value: T) => R
): OperatorFunction<T, R> =>
(source: Observable<T>): Observable<R> => {
return source.lift(
new CustomMapOperator<T, R>(project)
);
};

class CustomMapOperator<T, R> implements Operator<T, R> {
constructor(private project: (value: T) => R) {}

call(sub: Subscriber<R>, src: any): TeardownLogic {
return src.subscribe(
new CustomMapSubscriber(sub, this.project)
);
}
}``````
``````/* ... */
(source: Observable<T>): Observable<R> => {
return source.lift(
new CustomMapOperator<T, R>(project)
);
};

class CustomMapOperator<T, R> implements Operator<T, R> {
constructor(private project: (value: T) => R) {}

call(subscriber: Subscriber<R>, source: any): TeardownLogic {
return source.subscribe(
new CustomMapSubscriber(subscriber, this.project)
);
}
}

class CustomMapSubscriber<T, R> extends Subscriber<T> {
constructor(
destination: Subscriber<R>,
private project: (value: T) => R
) {
super(destination);
}

protected _next(value: T): void {
this.destination.next(this.project(value));
}
}``````

## Create from scratch

• bufferDelay
Â
• given a delay time parameter
• if more values are emitted in given time slot
they are spaced evenly with `delayTime`
• if value is emitted after specified delay time
it's emitted right away

## Summary

• Common use case ==> more descriptive name
• Chain of operations ==> one descriptive operator
• Our brand new custom operators
• Now we know how to harness the power of operators

## but remember...

• Don't overuse it
Â
• Test it!

# Thank you!

Â

## Any question?

Â

#### WarsawJS Workshop 38 - custom RxJS operators

By Chris TrzeÅ›niewski

# WarsawJS Workshop 38 - custom RxJS operators

• 100
Loading comments...