Many libraries are moving from instance methods to pipeable operators (e.g. RxJS, fp-ts, idb-keyval, Fluture, date-fns) because they have better bundling performance.
This works really well when you're only importing pipeable operators for one type (e.g. Observable
from RxJS), but if we're working with multiple types (e.g. Observable
and Option
from fp-ts) in the same file, you will inevitably face the problem of naming conflicts. For example:
import { map } from "rxjs/operators";
import { map } from "fp-ts/lib/Option";
One solution is to use namespace imports:
import * as option from "fp-ts/es6/Option";
import { Option } from "fp-ts/es6/Option";
import { pipe } from "fp-ts/lib/pipeable";
import { Observable } from "rxjs";
import * as observable from "rxjs/operators";
declare const numberOption$: Observable<Option<number>>;
declare const add1: (n: number) => number;
numberOption$.pipe(
observable.map(numberOption =>
pipe(
numberOption,
option.map(add1)
)
)
);
But they add a lot of noise to code. Observe how much more concise our code is when using instance methods:
numberOption$.map(numberOption => numberOption.map(add1));
This might not seem like much, but it quickly gets out of hand if you need to use more operators.
I wish it were possible to just import them like this:
Option
would need to be a type and a value at the same time. This would require it to be a class. A class with static methods.To make it tree-shakeable, it would need a
do
method as presented here.