staltz / xstream

An extremely intuitive, small, and fast functional reactive stream library for JavaScript
http://staltz.github.io/xstream/
MIT License
2.37k stars 137 forks source link

Co/Contravariant stream subtypes #286

Open DylanRJohnston opened 5 years ago

DylanRJohnston commented 5 years ago

Hey Staltz, I was wondering if you'd be open to exporting two interface subtypes of Stream<A>, one that contains all of the methods that are contravariant in A maybe called Sink<A> and one that contains all of the methods that are covariant in A maybe called Source<A>. This would allow for proper subtyping of methods that are expecting source / sink streams as Stream<A> is currently invariant in A.

For example

export type ContravariantMethods = 'addListener' | 'removeListener' | 'subscribe'
export interface Sink<A> extends Pick<Stream<A>, ContravariantMethods> {}

Most of the covariant methods on Stream<A> are static, with the exception of remember and debug. So the Source type makes less sense.

DylanRJohnston commented 5 years ago

Example

/* Type 'Stream<3>' is not assignable to type 'Stream<number>'.
  Types of property '_ils' are incompatible.
    Type 'InternalListener<3>[]' is not assignable to type 'InternalListener<number>[]'.
      Type 'InternalListener<3>' is not assignable to type 'InternalListener<number>'.
        Type 'number' is not assignable to type '3'.
*/
const number$: xs.Stream<number> = xs.Stream.of(3 as const)
// Totally fine
const number$: xs.Sink<number> = xs.Stream.of(3 as const)

More concretely, we have a general event sink that expects events payloads of a certain generic structure, and then a system generating events with a more specific type, e.g. a string literal for the event type.