Permalink
Browse files

fix(typings): Add generics so developer defines what redux Actions lo…

…ok like (#105)

When using TypeScript, you can now provide the expected action type by passing it as the first generic in `createEpicMiddleware<Action>(rootEpic)`. Most likely you'll use @types/flux-standard-action
  • Loading branch information...
jayphelps committed Sep 11, 2016
1 parent 29be27d commit 7b4214fb7dad28aa125a3545380b4e401cb6fa0e
Showing with 104 additions and 28 deletions.
  1. +2 −1 .gitignore
  2. +11 −11 index.d.ts
  3. +2 −1 package.json
  4. +83 −15 test/typings.ts
  5. +6 −0 typings.json
@@ -3,4 +3,5 @@ node_modules
lib
temp
dist
_book
_book
typings
@@ -1,21 +1,21 @@
import { Middleware, MiddlewareAPI, Action } from 'redux';
import { Middleware, MiddlewareAPI } from 'redux';
import { Observable } from 'rxjs/Observable';
import { Operator } from 'rxjs/Operator';
export declare class ActionsObservable extends Observable<Action> {
constructor(actionsSubject: Observable<Action>);
lift(operator: Operator<any, Action>) : ActionsObservable;
ofType(...key: any[]) : ActionsObservable;
export declare class ActionsObservable<T> extends Observable<T> {
constructor(input$: Observable<T>);
lift(operator: Operator<any, T>) : ActionsObservable<T>;
ofType(...key: any[]) : ActionsObservable<T>;
}
export declare interface Epic {
(action$: ActionsObservable, store: MiddlewareAPI<any>): Observable<Action>;
export declare interface Epic<T> {
(action$: ActionsObservable<T>, store: MiddlewareAPI<any>): Observable<T>;
}
export interface EpicMiddleware extends Middleware {
replaceEpic(nextEpic: Epic): void;
export interface EpicMiddleware<T> extends Middleware {
replaceEpic(nextEpic: Epic<T>): void;
}
export declare function createEpicMiddleware(rootEpic: Epic): EpicMiddleware;
export declare function createEpicMiddleware<T>(rootEpic: Epic<T>): EpicMiddleware<T>;
export declare function combineEpics(...epics: Epic[]): Epic;
export declare function combineEpics<T>(...epics: Epic<T>[]): Epic<T>;
@@ -13,7 +13,7 @@
"clean": "rimraf lib temp dist",
"check": "npm run lint && npm run test",
"test": "npm run lint && npm run build && npm run build:tests && mocha temp && npm run test:typings",
"test:typings": "tsc test/typings.ts --outFile temp/typings.js --target ES2015 --moduleResolution node",
"test:typings": "typings install && tsc index.d.ts typings/index.d.ts test/typings.ts --outDir temp --target ES5 --moduleResolution node && cd temp && node typings.js",
"shipit": "npm run clean && npm run lint && npm test && scripts/preprepublish.sh && npm publish",
"docs:clean": "rimraf _book",
"docs:prepare": "gitbook install",
@@ -93,6 +93,7 @@
"sinon": "1.17.5",
"symbol-observable": "^1.0.1",
"typescript": "^1.8.10",
"typings": "1.3.3",
"webpack": "^1.13.1",
"webpack-rxjs-externals": "~0.0.3"
}
@@ -1,50 +1,118 @@
import { createEpicMiddleware, Epic, combineEpics,
EpicMiddleware, ActionsObservable } from '../index';
import { Action, createStore, applyMiddleware } from 'redux';
import { expect } from 'chai';
import { createStore, applyMiddleware } from 'redux';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/mapTo';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
const epic1: Epic = (action$, store) =>
import { createEpicMiddleware, Epic, combineEpics,
EpicMiddleware, ActionsObservable } from '../';
interface FluxStandardAction {
type: string | symbol | any;
payload?: any;
error?: boolean | any;
meta?: any
}
const epic1: Epic<FluxStandardAction> = (action$: ActionsObservable<FluxStandardAction>, store) =>
action$.ofType('FIRST')
.mapTo({
type: 'first',
payload: store.getState()
});
const epic2: Epic = (action$, store) =>
action$.ofType('SECOND')
const epic2: Epic<FluxStandardAction> = (action$, store) =>
action$.ofType('SECOND', 'NEVER')
.mapTo('second')
.mergeMap(type => Observable.of({ type }));
const epic3: Epic = action$ =>
const epic3: Epic<FluxStandardAction> = action$ =>
action$.ofType('THIRD')
.mapTo({
type: 'third'
});
const epic4: Epic = () =>
const epic4: Epic<FluxStandardAction> = () =>
Observable.of({
type: 'fourth'
});
const rootEpic1: Epic = combineEpics(epic1, epic2, epic3, epic4);
const rootEpic2: Epic = combineEpics(epic1, epic2, epic3, epic4);
const epic5: Epic<FluxStandardAction> = (action$, store) =>
action$.ofType('FIFTH')
.flatMap(({ type, payload }) => Observable.of({
type: 'fifth',
payload
}));
const epicMiddleware: EpicMiddleware = createEpicMiddleware(rootEpic1);
const epic6 = (action$, store) =>
action$.ofType('SIXTH')
.map(({ type, payload }) => ({
type: 'sixth',
payload
}));
epicMiddleware.replaceEpic(rootEpic2);
const rootEpic1: Epic<FluxStandardAction> = combineEpics<FluxStandardAction>(epic1, epic2, epic3, epic4, epic5, epic6);
const rootEpic2 = combineEpics(epic1, epic2, epic3, epic4, epic5, epic6);
const epicMiddleware1: EpicMiddleware<FluxStandardAction> = createEpicMiddleware<FluxStandardAction>(rootEpic1);
const epicMiddleware2 = createEpicMiddleware(rootEpic2);
// should be a constructor that returns an observable
const actionsSubject = Observable.create(() => {});
const aoTest: Observable<Action> = new ActionsObservable(actionsSubject);
const input$ = Observable.create(() => {});
const action$: ActionsObservable<FluxStandardAction> = new ActionsObservable<FluxStandardAction>(input$);
const reducer = (state = [], action) => state.concat(action);
const store = createStore(
reducer,
applyMiddleware(epicMiddleware)
applyMiddleware(epicMiddleware1, epicMiddleware2)
);
epicMiddleware1.replaceEpic(rootEpic2);
epicMiddleware2.replaceEpic(rootEpic1)
store.dispatch({ type: 'FIRST' });
store.dispatch({ type: 'SECOND' });
store.dispatch({ type: 'FIFTH', payload: 'fifth-payload' });
store.dispatch({ type: 'SIXTH', payload: 'sixth-payload' });
expect(store.getState()).to.deep.equal([
{ "type": "@@redux/INIT" },
{ "type": "fourth" },
{ "type": "fourth" },
{ "type": "@@redux-observable/EPIC_END" },
{ "type": "fourth" },
{ "type": "@@redux-observable/EPIC_END" },
{ "type": "fourth" },
{ "type": "FIRST" },
{ "type": "first",
"payload": [
{ "type": "@@redux/INIT" },
{ "type": "fourth" },
{ "type": "fourth" },
{ "type": "@@redux-observable/EPIC_END" },
{ "type": "fourth" },
{ "type": "@@redux-observable/EPIC_END" }
]
},
{ "type": "first",
"payload": [
{ "type": "@@redux/INIT" },
{ "type": "fourth" },
{ "type": "fourth" },
{ "type": "@@redux-observable/EPIC_END" }
]
},
{ "type": "SECOND" },
{ "type": "second" },
{ "type": "second" },
{ "type": "FIFTH", "payload": "fifth-payload" },
{ "type": "fifth", "payload": "fifth-payload" },
{ "type": "fifth", "payload": "fifth-payload" },
{ "type": "SIXTH", "payload": "sixth-payload" },
{ "type": "sixth", "payload": "sixth-payload" },
{ "type": "sixth", "payload": "sixth-payload" }
]);
console.log('typings.ts: OK');
@@ -0,0 +1,6 @@
{
"globalDependencies": {
"chai": "registry:dt/chai#3.4.0+20160601211834",
"es6-shim": "registry:dt/es6-shim#0.31.2+20160602141504"
}
}

0 comments on commit 7b4214f

Please sign in to comment.