diff --git a/.eslintrc b/.eslintrc index 923b41bdc2..568a06f94d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,7 +14,8 @@ "strict": [2, "never"], "react/jsx-uses-react": 2, "react/jsx-uses-vars": 2, - "react/react-in-jsx-scope": 2 + "react/react-in-jsx-scope": 2, + "no-unused-vars": 0 }, "plugins": [ "react" diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000000..369768b7ad --- /dev/null +++ b/.flowconfig @@ -0,0 +1,9 @@ +[ignore] +.*/lib +.*/test + +[include] + +[libs] + +[options] diff --git a/src/Redux.js b/src/Redux.js index f60cc5aa52..f912d48732 100644 --- a/src/Redux.js +++ b/src/Redux.js @@ -1,15 +1,24 @@ +/* @flow */ + import createDispatcher from './createDispatcher'; import composeStores from './utils/composeStores'; import thunkMiddleware from './middleware/thunk'; +import { State, Action, Dispatch, Dispatcher } from './types'; + export default class Redux { - constructor(dispatcher, initialState) { + state: State; + listeners: Function[]; + dispatcher: Dispatcher; + dispatchFn: Dispatch; + + constructor(dispatcher: Dispatcher, initialState: State): void { if (typeof dispatcher === 'object') { // A shortcut notation to use the default dispatcher - dispatcher = createDispatcher( + dispatcher = (createDispatcher( composeStores(dispatcher), getState => [thunkMiddleware(getState)] - ); + )); } this.state = initialState; @@ -17,35 +26,35 @@ export default class Redux { this.replaceDispatcher(dispatcher); } - getDispatcher() { + getDispatcher(): Dispatcher { return this.dispatcher; } - replaceDispatcher(nextDispatcher) { + replaceDispatcher(nextDispatcher: Dispatcher): void { this.dispatcher = nextDispatcher; - this.dispatchFn = nextDispatcher(this.state, ::this.setState); + this.dispatchFn = nextDispatcher(this.state, this.setState.bind(this)); } - dispatch(action) { + dispatch(action: Action): any { return this.dispatchFn(action); } - getState() { + getState(): State { return this.state; } - setState(nextState) { + setState(nextState: State): State { this.state = nextState; this.listeners.forEach(listener => listener()); return nextState; } - subscribe(listener) { - const { listeners } = this; + subscribe(listener: Function): () => void { + var { listeners } = this; listeners.push(listener); - return function unsubscribe () { - const index = listeners.indexOf(listener); + return function unsubscribe() { + var index = listeners.indexOf(listener); listeners.splice(index, 1); }; } diff --git a/src/createDispatcher.js b/src/createDispatcher.js index 9a928b8c94..e40c4571dd 100644 --- a/src/createDispatcher.js +++ b/src/createDispatcher.js @@ -1,15 +1,25 @@ +/* @flow */ + import compose from './utils/composeMiddleware'; -export default function createDispatcher(store, middlewares = []) { - return function dispatcher(initialState, setState) { - let state = setState(store(initialState, {})); +import type { Middleware, Store, Action, State, Dispatcher } from './types'; + +export default function createDispatcher( + store: Store, + middlewares: (Middleware[] | (getState: () => State) => Middleware[]) = [] +): Dispatcher { + return function dispatcher( + initialState: State, + setState: (state: State) => State + ) { + var state: State = setState(store(initialState, {})); - function dispatch(action) { + function dispatch(action: Action): Action { state = setState(store(state, action)); return action; } - function getState() { + function getState(): State { return state; } diff --git a/src/types.js b/src/types.js new file mode 100644 index 0000000000..a0797dbe1f --- /dev/null +++ b/src/types.js @@ -0,0 +1,13 @@ +/* @flow */ + +export type State = any; + +export type Action = any; + +export type Store = (state: State, action: Action) => State; + +export type Dispatch = (action: Action) => any; + +export type Dispatcher = (state: State, setState: (nextState: State) => State) => Dispatch; + +export type Middleware = (next: Dispatch | Middleware) => (Dispatch | Middleware); diff --git a/src/utils/composeMiddleware.js b/src/utils/composeMiddleware.js index fcedfc20a1..811f049566 100644 --- a/src/utils/composeMiddleware.js +++ b/src/utils/composeMiddleware.js @@ -1,3 +1,9 @@ -export default function compose(...middlewares) { - return middlewares.reduceRight((composed, m) => m(composed)); +/* @flow */ + +import { Middleware, Dispatch } from '../types'; + +export default function compose(...middlewares: Middleware[]): Middleware { + return middlewares.reduceRight( + (composed: Middleware | Dispatch, m: Middleware | Dispatch) => m(composed) + ); } diff --git a/src/utils/composeStores.js b/src/utils/composeStores.js index 9aa2442a80..48b210b2b7 100644 --- a/src/utils/composeStores.js +++ b/src/utils/composeStores.js @@ -1,9 +1,13 @@ +/* @flow */ + import mapValues from 'lodash/object/mapValues'; -export default function composeStores(stores) { - return function Composition(atom = {}, action) { +import type { Store, Action, State } from '../types'; + +export default function composeStores(stores: Store[]): Store { + return function Composition(state: State = {}, action: Action) { return mapValues(stores, (store, key) => - store(atom[key], action) + store(state[key], action) ); }; }