Skip to content

Commit

Permalink
Merge pull request reduxjs#1537 from Igorbek/ts-def-improv
Browse files Browse the repository at this point in the history
Add state type to dispatch interface
  • Loading branch information
aikoven committed Apr 4, 2016
2 parents e6d1780 + 658fa6f commit 3388903
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 21 deletions.
18 changes: 10 additions & 8 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>;
* transform, delay, ignore, or otherwise interpret actions or async actions
* before passing them to the next middleware.
*/
export type Dispatch = (action: any) => any;
export interface Dispatch<S> {
<A extends Action>(action: A): A;
}

/**
* Function to remove listener added by `Store.subscribe()`.
Expand Down Expand Up @@ -136,7 +138,7 @@ export interface Store<S> {
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
* return something else (for example, a Promise you can await).
*/
dispatch: Dispatch;
dispatch: Dispatch<S>;

/**
* Reads the state tree managed by the store.
Expand Down Expand Up @@ -251,7 +253,7 @@ export const createStore: StoreCreator;
/* middleware */

export interface MiddlewareAPI<S> {
dispatch: Dispatch;
dispatch: Dispatch<S>;
getState(): S;
}

Expand All @@ -265,7 +267,7 @@ export interface MiddlewareAPI<S> {
* asynchronous API call into a series of synchronous actions.
*/
export interface Middleware {
<S>(api: MiddlewareAPI<S>): (next: Dispatch) => (action: any) => any;
<S>(api: MiddlewareAPI<S>): (next: Dispatch<S>) => Dispatch<S>;
}

/**
Expand Down Expand Up @@ -337,19 +339,19 @@ export interface ActionCreatorsMapObject {
* creator wrapped into the `dispatch` call. If you passed a function as
* `actionCreator`, the return value will also be a single function.
*/
export function bindActionCreators<A extends ActionCreator<any>>(actionCreator: A, dispatch: Dispatch): A;
export function bindActionCreators<A extends ActionCreator<any>>(actionCreator: A, dispatch: Dispatch<any>): A;

export function bindActionCreators<
A extends ActionCreator<any>,
B extends ActionCreator<any>
>(actionCreator: A, dispatch: Dispatch): B;
>(actionCreator: A, dispatch: Dispatch<any>): B;

export function bindActionCreators<M extends ActionCreatorsMapObject>(actionCreators: M, dispatch: Dispatch): M;
export function bindActionCreators<M extends ActionCreatorsMapObject>(actionCreators: M, dispatch: Dispatch<any>): M;

export function bindActionCreators<
M extends ActionCreatorsMapObject,
N extends ActionCreatorsMapObject
>(actionCreators: M, dispatch: Dispatch): N;
>(actionCreators: M, dispatch: Dispatch<any>): N;


/* compose */
Expand Down
6 changes: 3 additions & 3 deletions test/typescript/actionCreators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ const addTodo: ActionCreator<AddTodoAction> = (text: string) => ({

const addTodoAction: AddTodoAction = addTodo('test');

type AddTodoThunk = (dispatch: Dispatch) => AddTodoAction;
type AddTodoThunk = (dispatch: Dispatch<any>) => AddTodoAction;

const addTodoViaThunk: ActionCreator<AddTodoThunk> = (text: string) =>
(dispatch: Dispatch) => ({
(dispatch: Dispatch<any>) => ({
type: 'ADD_TODO',
text
})

declare const dispatch: Dispatch;
declare const dispatch: Dispatch<any>;

const boundAddTodo = bindActionCreators(addTodo, dispatch);

Expand Down
12 changes: 8 additions & 4 deletions test/typescript/dispatch.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import {Dispatch, Action} from "../../index.d.ts";


declare const dispatch: Dispatch;

declare const dispatch: Dispatch<any>;

const dispatchResult: Action = dispatch({type: 'TYPE'});


type Thunk<O> = () => O;
// thunk
declare module "../../index.d.ts" {
export interface Dispatch<S> {
<R>(asyncAction: (dispatch: Dispatch<S>, getState: () => S) => R): R;
}
}

const dispatchThunkResult: number = dispatch(() => 42);
const dispatchedTimerId: number = dispatch(d => setTimeout(() => d({type: 'TYPE'}), 1000));
17 changes: 11 additions & 6 deletions test/typescript/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@ import {
applyMiddleware, createStore, Dispatch, Reducer, Action
} from "../../index.d.ts";

declare module "../../index.d.ts" {
export interface Dispatch<S> {
<R>(asyncAction: (dispatch: Dispatch<S>, getState: () => S) => R): R;
}
}

type Thunk<S, O> = (dispatch: Dispatch, getState?: () => S) => O;
type Thunk<S, O> = (dispatch: Dispatch<S>, getState: () => S) => O;

const thunkMiddleware: Middleware =
<S>({dispatch, getState}: MiddlewareAPI<S>) =>
(next: Dispatch) =>
<A, B>(action: A | Thunk<S, B>): B =>
(next: Dispatch<S>) =>
<A extends Action, B>(action: A | Thunk<S, B>): B|Action =>
typeof action === 'function' ?
(<Thunk<S, B>>action)(dispatch, getState) :
<B>next(<A>action)
next(<A>action)


const loggerMiddleware: Middleware =
<S>({getState}: MiddlewareAPI<S>) =>
(next: Dispatch) =>
(next: Dispatch<S>) =>
(action: any): any => {
console.log('will dispatch', action)

Expand Down Expand Up @@ -47,7 +52,7 @@ const storeWithThunkMiddleware = createStore(
);

storeWithThunkMiddleware.dispatch(
(dispatch: Dispatch, getState: () => State) => {
(dispatch, getState) => {
const todos: string[] = getState().todos;
dispatch({type: 'ADD_TODO'})
}
Expand Down

0 comments on commit 3388903

Please sign in to comment.