xstream
xstream copied to clipboard
Static Land style API
Hey guys, [email protected]
moved away from a method chaining API to a more static land style API which means it doesn't gel very well with xstream anymore. Would you be opposed to exporting all of operator methods as static functions curried in their stream argument? Right now I have a little helper file that re-exports methods as needed.
e.g.
export const map = <A, B>(f: (a: A) => B)) => ($: Stream<A>): Stream<B> => $.map(F)
I'm not sure how to get this to work with operators that work on Streams and MemoryStreams. I see a few different options.
- Namespace the operators, something like
mapMemory
or maybe have them as seperate modules so they can imported asimport xs from 'xstream/static'
andimport xsm from 'xstream/static/memory
or something like that. - Use the higher kinded types method developed by
fp-ts
, but it's pretty difficult to understand for new users and would probably tie these two libraries too close together (Maybe this belongs as a seperate package?) - Use a conditional type for the return. This is in a sense copying the higher kinded type method from fp-ts, but for a known finite domain of Functors. Something like this
type AnyStream<A> = Stream<A> | MemoryStream<A>
type StreamOf<S extends AnyStream<unknown>, B>
= S extends MemoryStream<unknown> ? MemoryStream<B>
: S extends Stream<unknown> ? Stream<B>
: unknown
export const map = <A, B>(f: (a: A) => B) => <S extends Stream<A>>($: S): StreamOf<S, B> => ($.map as any)(f)
I think 3 should work fine given Stream<A>
is invariant in A
.
Just realised Typescript already has pattern matching for types, function overloads!
type AnyStream<A> = Stream<A> | MemoryStream<A>
interface StreamOperator<A, B = A> {
($: MemoryStream<A>): MemoryStream<B>
($: Stream<A>): Stream<B>
}
export const map = <A, B>(f: (a: A) => B): StreamOperator<A, B> => ($: AnyStream<A>) =>
($ as any).map(f)