Last active
August 2, 2017 07:36
-
-
Save typoerr/e2b7142cc474b2301d9d0d6bed49a007 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { EventEmitter2 } from 'eventemitter2'; | |
import { Stream, fromEvent, mergeArray } from 'most'; | |
import { MiddlewareAPI, Middleware, Dispatch } from 'redux'; | |
// ================================================================== | |
// EventSource | |
// ================================================================== | |
export type Listener<T, K extends keyof T> = (arg: T[K]) => any; | |
export class TypedEventEmitter<T = any> extends EventEmitter2 { | |
on<K extends keyof T>(event: K, listener: Listener<T, K>) { | |
return super.on(event, listener); | |
} | |
once<K extends keyof T>(event: K, listener: Listener<T, K>) { | |
return super.once(event, listener); | |
} | |
off<K extends keyof T>(event: K, listener: Listener<T, K>) { | |
return super.removeListener(event, listener); | |
} | |
emit<K extends keyof T>(event: K, arg: T[K]) { | |
return super.emit(event, arg); | |
} | |
dispatch<K extends keyof T>(event: K, arg: T[K]) { | |
return super.emitAsync(event, arg); | |
} | |
} | |
// ================================================================== | |
// Listen with stream | |
// ================================================================== | |
export function select<T, K extends keyof T>(target: K, src: TypedEventEmitter<T>): Stream<T[K]> { | |
return fromEvent(target, src) as any; | |
} | |
// ================================================================== | |
// Redux Middleware | |
// ================================================================== | |
export interface RequireCtx { | |
eventSource: TypedEventEmitter; | |
} | |
export interface MergedCtx<A, S> { | |
next: TypedEventEmitter<A>['dispatch']; | |
store: MiddlewareAPI<S>; | |
} | |
export interface Epic<A, S, C = any> { | |
(eventSource: TypedEventEmitter<A>, ctx: MergedCtx<A, S> & C): Stream<any>; | |
} | |
export function createEpicMiddleware<C extends RequireCtx>(context: C) { | |
return <S = any>(epics: Epic<any, S, C>[]) => { | |
const middleware = (store: MiddlewareAPI<S>) => (next: Dispatch<S>) => { | |
const emitter = context.eventSource; | |
const ctx = Object.assign({}, context, { | |
store, | |
next: emitter.dispatch.bind(emitter) | |
}); | |
emitter.prependAny((type, payload) => next({ type, payload })); | |
mergeArray(epics.map(ep => ep(emitter, ctx))).drain(); | |
return next; | |
}; | |
return middleware as any as Middleware; | |
}; | |
} |
Author
typoerr
commented
Aug 2, 2017
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment