Skip to content

Commit

Permalink
[redux_v3.x.x] Annotate for flow past 0.89 (#3288)
Browse files Browse the repository at this point in the history
- $Subtype is deprecated after 0.89
- Rest annotations follow #3223
  • Loading branch information
wgao19 authored and pascalduez committed May 4, 2019
1 parent 6347e0d commit 537401f
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 0 deletions.
93 changes: 93 additions & 0 deletions definitions/npm/redux_v3.x.x/flow_v0.89.x-/redux_v3.x.x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
declare module 'redux' {
/*
S = State
A = Action
D = Dispatch
*/

declare export type DispatchAPI<A> = (action: A) => A;

declare export type Dispatch<A: { type: * }> = DispatchAPI<A>;

declare export type MiddlewareAPI<S, A, D = Dispatch<A>> = {
dispatch: D,
getState(): S,
};

declare export type Store<S, A, D = Dispatch<A>> = {
// rewrite MiddlewareAPI members in order to get nicer error messages (intersections produce long messages)
dispatch: D,
getState(): S,
subscribe(listener: () => void): () => void,
replaceReducer(nextReducer: Reducer<S, A>): void,
};

declare export type Reducer<S, A> = (state: S | void, action: A) => S;

declare export type CombinedReducer<S, A> = (
state: ($Shape<S> & {}) | void,
action: A
) => S;

declare export type Middleware<S, A, D = Dispatch<A>> = (
api: MiddlewareAPI<S, A, D>
) => (next: D) => D;

declare export type StoreCreator<S, A, D = Dispatch<A>> = {
(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>,
(
reducer: Reducer<S, A>,
preloadedState: S,
enhancer?: StoreEnhancer<S, A, D>
): Store<S, A, D>,
};

declare export type StoreEnhancer<S, A, D = Dispatch<A>> = (
next: StoreCreator<S, A, D>
) => StoreCreator<S, A, D>;

declare export function createStore<S, A, D>(
reducer: Reducer<S, A>,
enhancer?: StoreEnhancer<S, A, D>
): Store<S, A, D>;
declare export function createStore<S, A, D>(
reducer: Reducer<S, A>,
preloadedState?: S,
enhancer?: StoreEnhancer<S, A, D>
): Store<S, A, D>;

declare export function applyMiddleware<S, A, D>(
...middlewares: Array<Middleware<S, A, D>>
): StoreEnhancer<S, A, D>;

declare export type ActionCreator<A, B> = (...args: Array<B>) => A;
declare export type ActionCreators<K, A> = {
[key: K]: ActionCreator<A, any>,
};

declare export function bindActionCreators<
A,
C: ActionCreator<A, any>,
D: DispatchAPI<A>
>(
actionCreator: C,
dispatch: D
): C;
declare export function bindActionCreators<
A,
K,
C: ActionCreators<K, A>,
D: DispatchAPI<A>
>(
actionCreators: C,
dispatch: D
): C;

declare export function combineReducers<O: {}, A>(
reducers: O
): CombinedReducer<$ObjMap<O, <S>(r: Reducer<S, any>) => S>, A>;

declare export var compose: $Compose;
}
38 changes: 38 additions & 0 deletions definitions/npm/redux_v3.x.x/flow_v0.89.x-/test_applyMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// @flow
import type { Store as ReduxStore, MiddlewareAPI } from 'redux';
import { applyMiddleware, createStore } from 'redux';

type State = Array<number>;
type Action = { type: 'A' };
type Store = ReduxStore<State, Action>;
const reducer = (state: State = [], action: Action): State => state;

//
// applyMiddleware API
//

applyMiddleware();
applyMiddleware(api => next => next);
// $ExpectError
applyMiddleware('wrong');

//
// interaction with createStore
//

createStore(reducer, [1], applyMiddleware(api => next => next));
createStore(
reducer,
[1],
applyMiddleware((api: MiddlewareAPI<State, Action>) => {
// $ExpectError
const s: number = api.getState(); // wrong return type
// $ExpectError
api.dispatch({ type: 'wrong' }); // wrong action
// $ExpectError
api.replaceReducer(() => ({})); // wrong reducer
// $ExpectError
api.subscribe(() => 'wrong'); // wrong subscriber
return next => next;
})
);
48 changes: 48 additions & 0 deletions definitions/npm/redux_v3.x.x/flow_v0.89.x-/test_combineReducers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// @flow
import type { Reducer } from 'redux';
import { combineReducers } from 'redux';

type Action = { type: 'A' } | { type: 'B' };
type AState = { foo: number };
const initialAState: AState = { foo: 1 };
const reducerA: Reducer<AState, Action> = (state = initialAState, action) => {
return state;
};
type State = {
a: AState,
name: string,
age: number,
};

//
// combineReducers API
//

const initialName = 'initialName';
function reducerName(name: string = initialName, action: Action): string {
return name;
}

const initialAge = 0;
function reducerAge(age: number = initialAge, action: Action): number {
return age;
}

// ok
const reducer0: Reducer<State, Action> = combineReducers({
a: reducerA,
name: reducerName,
age: reducerAge,
});

// $ExpectError
combineReducers(); // wrong reducers argument
// $ExpectError
combineReducers([]); // wrong reducers argument

// $ExpectError
const reducer1: Reducer<State, Action> = combineReducers({
a: reducerA,
name: reducerName,
// missing age reducer
});
47 changes: 47 additions & 0 deletions definitions/npm/redux_v3.x.x/flow_v0.89.x-/test_createStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// @flow
import type { Store as ReduxStore, StoreEnhancer } from 'redux';
import { createStore } from 'redux';

type State = Array<number>;
type Action = { type: 'A' };
type Store = ReduxStore<State, Action>;
const reducer = (state: State = [], action: Action): State => state;

//
// createStore API
//

// $ExpectError
const store1: Store = createStore(() => ({})); // wrong reducer
const store2: Store = createStore(reducer);
// $ExpectError
const store3: Store = createStore(reducer, {}); // wrong initialState shape
const store4: Store = createStore(reducer, []);
// $ExpectError
const store5: Store = createStore(reducer, ['wrong']); // wrong initialState content
const store6: Store = createStore(reducer, [1]);
// $ExpectError
const store7: Store = createStore(reducer, [1], 'wrong'); // wrong enhancer
declare var myEnhancer: StoreEnhancer<State, Action>;
const store8: Store = createStore(reducer, [1], myEnhancer);
const store9: Store = createStore(reducer, undefined, myEnhancer);

//
// store members
//

const s: State = store2.getState();
// $ExpectError
const s: number = store2.getState(); // wrong return type

store2.dispatch({ type: 'A' });
// $ExpectError
store2.dispatch({ type: 'wrong' }); // wrong action

store2.replaceReducer(reducer);
// $ExpectError
store2.replaceReducer(() => ({})); // wrong reducer

store2.subscribe(() => {});
// $ExpectError
store2.subscribe(() => 'wrong'); // wrong subscriber
69 changes: 69 additions & 0 deletions definitions/npm/redux_v3.x.x/flow_v0.89.x-/test_custom_dispatch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// @flow
import type {
Store as ReduxStore,
DispatchAPI,
MiddlewareAPI,
StoreEnhancer,
} from 'redux';
import { applyMiddleware, bindActionCreators, createStore } from 'redux';

type State = Array<number>;
type Action = { type: 'A' };
type Thunk = (dispatch: Dispatch, getState: () => State) => void;
type Dispatch = DispatchAPI<Action | Thunk>;
type Store = ReduxStore<State, Action, Dispatch>;
const reducer = (state: State = [], action: Action): State => state;

//
// applyMiddleware interaction with createStore
//

createStore(
reducer,
[1],
applyMiddleware((api: MiddlewareAPI<State, Action, Dispatch>) => {
api.dispatch({ type: 'A' });
// $ExpectError
api.dispatch({ type: 'wrong' }); // wrong action

api.dispatch((dispatch, getState) => {});
// $ExpectError
api.dispatch(() => false);

return next => next;
})
);

//
// bindActionCreators API
//

declare var dispatch: Dispatch;

const ac1 = bindActionCreators((n: number) => ({ type: 'A' }), dispatch);
ac1(1);
// $ExpectError
bindActionCreators((n: number) => ({ type: 'wrong' }), dispatch); // wrong action

const ac2 = bindActionCreators(
(n: number) => (dispatch, getState) => {},
dispatch
);
ac2(1);
// $ExpectError
bindActionCreators((n: number) => (dispatch, getState) => 'wrong', dispatch); // wrong thunk

//
// createStore API
//

declare var myEnhancer: StoreEnhancer<State, Action, Dispatch>;
const store: Store = createStore(reducer, [1], myEnhancer);

store.dispatch({ type: 'A' });
// $ExpectError
store.dispatch({ type: 'wrong' }); // wrong action

store.dispatch((dispatch, getState) => {});
// $ExpectError
store.dispatch((dispatch, getState) => false); // wrong action

0 comments on commit 537401f

Please sign in to comment.