Skip to content

Addition to your PR #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>;

/* store */

export interface MiddlewareDispatch {
<TMiddlewareAction, TMiddlewareActionResult>(action: TMiddlewareAction): TMiddlewareActionResult;
}

/**
* A *dispatching function* (or simply *dispatch function*) is a function that
* accepts an action or an async action; it then may or may not dispatch one
Expand All @@ -97,8 +93,8 @@ export interface MiddlewareDispatch {
* transform, delay, ignore, or otherwise interpret actions or async actions
* before passing them to the next middleware.
*/
export interface Dispatch extends MiddlewareDispatch {
(action: Action): Action;
export interface Dispatch<S> {
<A extends Action>(action: A): A;
}

/**
Expand Down Expand Up @@ -142,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 @@ -257,7 +253,7 @@ export const createStore: StoreCreator;
/* middleware */

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

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

/**
Expand Down Expand Up @@ -343,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
14 changes: 9 additions & 5 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'});

// thunk
declare module "../../index.d.ts" {
export interface Dispatch<S> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't S be inferred as well? I wouldn't add it directly as a parameter to Dispatch, because it's specific to Thunk. Other middlewares will have their own parameters too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The S here is a part of dispatch's contract defined in the index.d.ts. I've added it because some results may depend on it. And, moreover, S is always known by dispatch - its a part of typed store.

<R>(asyncAction: (dispatch: Dispatch<S>, getState: () => S) => R): R;
}
}

type Thunk<O> = () => O;

const dispatchThunkResult: number = dispatch<Thunk<number>, number>(() => 42);
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