Skip to content

Commit

Permalink
Mapped type for combineReducers in index.d.ts (#2182)
Browse files Browse the repository at this point in the history
* Add mapped type for combineReducers in index.d.ts

Updated typescript to 2.1.4
Updated typescript-definition-tester to 0.0.5
Updated typescript tests to use proper import
Added mapped type to index.d.ts

* add strict null check for reducer

Updated Reducer<S> type in index.d.ts
Add strictNullChecks flag to typescript spec
  • Loading branch information
mkusher authored and timdorr committed Jan 5, 2017
1 parent 0bca1b5 commit e90c835
Show file tree
Hide file tree
Showing 11 changed files with 4,231 additions and 35 deletions.
26 changes: 14 additions & 12 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export interface Action {
*
* @template S State object type.
*/
export type Reducer<S> = <A extends Action>(state: S, action: A) => S;
export type Reducer<S> = <A extends Action>(state: S | undefined, action: A) => S;

/**
* Object whose values correspond to different reducer functions.
*/
export interface ReducersMapObject {
[key: string]: Reducer<any>;
export type ReducersMapObject<S> = {
[K in keyof S]: Reducer<S[K]>;
}

/**
Expand All @@ -70,7 +70,7 @@ export interface ReducersMapObject {
* @returns A reducer function that invokes every reducer inside the passed
* object, and builds a state object with the same shape.
*/
export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>;
export function combineReducers<S>(reducers: ReducersMapObject<S>): Reducer<S>;


/* store */
Expand All @@ -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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@
"isparta": "^4.0.0",
"mocha": "^2.2.5",
"rimraf": "^2.3.4",
"typescript": "^1.8.0",
"typescript-definition-tester": "0.0.4",
"typescript": "^2.1.0",
"typescript-definition-tester": "0.0.5",
"webpack": "^1.9.6"
},
"npmName": "redux",
Expand Down
3 changes: 3 additions & 0 deletions test/typescript.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ describe('TypeScript definitions', function () {
tt.compileDirectory(
__dirname + '/typescript',
fileName => fileName.match(/\.ts$/),
{
strictNullChecks: true
},
() => done()
)
})
Expand Down
8 changes: 4 additions & 4 deletions test/typescript/actionCreators.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
ActionCreator, Action, Dispatch,
bindActionCreators, ActionCreatorsMapObject
} from "../../index.d.ts";
} from "../../";


interface AddTodoAction extends Action {
Expand All @@ -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
2 changes: 1 addition & 1 deletion test/typescript/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Action as ReduxAction} from "../../index.d.ts";
import {Action as ReduxAction} from "../../";


namespace FSA {
Expand Down
2 changes: 1 addition & 1 deletion test/typescript/compose.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {compose} from "../../index.d.ts";
import {compose} from "../../";

// copied from DefinitelyTyped/compose-function

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


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


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


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

const dispatchThunkResult: number = dispatch(() => 42);
19 changes: 12 additions & 7 deletions test/typescript/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import {
Middleware, MiddlewareAPI,
applyMiddleware, createStore, Dispatch, Reducer, Action
} from "../../index.d.ts";
} from "../../";

declare module "../../" {
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: Dispatch<State>, getState: () => State) => {
const todos: string[] = getState().todos;
dispatch({type: 'ADD_TODO'})
}
Expand Down
5 changes: 2 additions & 3 deletions test/typescript/reducers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Reducer, Action, combineReducers,
ReducersMapObject
} from "../../index.d.ts";
} from "../../";


type TodosState = string[];
Expand Down Expand Up @@ -47,8 +47,7 @@ type RootState = {
counter: CounterState;
}


const rootReducer: Reducer<RootState> = combineReducers<RootState>({
const rootReducer: Reducer<RootState> = combineReducers({
todos: todosReducer,
counter: counterReducer,
})
Expand Down
2 changes: 1 addition & 1 deletion test/typescript/store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Store, createStore, Reducer, Action, StoreEnhancer,
StoreCreator, Unsubscribe
} from "../../index.d.ts";
} from "../../";


type State = {
Expand Down
Loading

0 comments on commit e90c835

Please sign in to comment.