Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e90c835

Browse files
mkushertimdorr
authored andcommittedJan 5, 2017
Mapped type for combineReducers in index.d.ts (#2182)
* 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
1 parent 0bca1b5 commit e90c835

11 files changed

+4231
-35
lines changed
 

‎index.d.ts

+14-12
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ export interface Action {
4343
*
4444
* @template S State object type.
4545
*/
46-
export type Reducer<S> = <A extends Action>(state: S, action: A) => S;
46+
export type Reducer<S> = <A extends Action>(state: S | undefined, action: A) => S;
4747

4848
/**
4949
* Object whose values correspond to different reducer functions.
5050
*/
51-
export interface ReducersMapObject {
52-
[key: string]: Reducer<any>;
51+
export type ReducersMapObject<S> = {
52+
[K in keyof S]: Reducer<S[K]>;
5353
}
5454

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

7575

7676
/* store */
@@ -93,7 +93,9 @@ export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>;
9393
* transform, delay, ignore, or otherwise interpret actions or async actions
9494
* before passing them to the next middleware.
9595
*/
96-
export type Dispatch = (action: any) => any;
96+
export interface Dispatch<S> {
97+
<A extends Action>(action: A): A;
98+
}
9799

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

141143
/**
142144
* Reads the state tree managed by the store.
@@ -251,7 +253,7 @@ export const createStore: StoreCreator;
251253
/* middleware */
252254

253255
export interface MiddlewareAPI<S> {
254-
dispatch: Dispatch;
256+
dispatch: Dispatch<S>;
255257
getState(): S;
256258
}
257259

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

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

342344
export function bindActionCreators<
343345
A extends ActionCreator<any>,
344346
B extends ActionCreator<any>
345-
>(actionCreator: A, dispatch: Dispatch): B;
347+
>(actionCreator: A, dispatch: Dispatch<any>): B;
346348

347-
export function bindActionCreators<M extends ActionCreatorsMapObject>(actionCreators: M, dispatch: Dispatch): M;
349+
export function bindActionCreators<M extends ActionCreatorsMapObject>(actionCreators: M, dispatch: Dispatch<any>): M;
348350

349351
export function bindActionCreators<
350352
M extends ActionCreatorsMapObject,
351353
N extends ActionCreatorsMapObject
352-
>(actionCreators: M, dispatch: Dispatch): N;
354+
>(actionCreators: M, dispatch: Dispatch<any>): N;
353355

354356

355357
/* compose */

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100
"isparta": "^4.0.0",
101101
"mocha": "^2.2.5",
102102
"rimraf": "^2.3.4",
103-
"typescript": "^1.8.0",
104-
"typescript-definition-tester": "0.0.4",
103+
"typescript": "^2.1.0",
104+
"typescript-definition-tester": "0.0.5",
105105
"webpack": "^1.9.6"
106106
},
107107
"npmName": "redux",

‎test/typescript.spec.js

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ describe('TypeScript definitions', function () {
88
tt.compileDirectory(
99
__dirname + '/typescript',
1010
fileName => fileName.match(/\.ts$/),
11+
{
12+
strictNullChecks: true
13+
},
1114
() => done()
1215
)
1316
})

‎test/typescript/actionCreators.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
ActionCreator, Action, Dispatch,
33
bindActionCreators, ActionCreatorsMapObject
4-
} from "../../index.d.ts";
4+
} from "../../";
55

66

77
interface AddTodoAction extends Action {
@@ -15,15 +15,15 @@ const addTodo: ActionCreator<AddTodoAction> = (text: string) => ({
1515

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

18-
type AddTodoThunk = (dispatch: Dispatch) => AddTodoAction;
18+
type AddTodoThunk = (dispatch: Dispatch<any>) => AddTodoAction;
1919

2020
const addTodoViaThunk: ActionCreator<AddTodoThunk> = (text: string) =>
21-
(dispatch: Dispatch) => ({
21+
(dispatch: Dispatch<any>) => ({
2222
type: 'ADD_TODO',
2323
text
2424
})
2525

26-
declare const dispatch: Dispatch;
26+
declare const dispatch: Dispatch<any>;
2727

2828
const boundAddTodo = bindActionCreators(addTodo, dispatch);
2929

‎test/typescript/actions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Action as ReduxAction} from "../../index.d.ts";
1+
import {Action as ReduxAction} from "../../";
22

33

44
namespace FSA {

‎test/typescript/compose.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {compose} from "../../index.d.ts";
1+
import {compose} from "../../";
22

33
// copied from DefinitelyTyped/compose-function
44

‎test/typescript/dispatch.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import {Dispatch, Action} from "../../index.d.ts";
1+
import {Dispatch, Action} from "../../";
22

33

4-
declare const dispatch: Dispatch;
4+
declare const dispatch: Dispatch<any>;
55

66

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

9-
10-
type Thunk<O> = () => O;
9+
declare module "../../" {
10+
export interface Dispatch<S> {
11+
<R>(asyncAction: (dispatch: Dispatch<S>, getState: () => S) => R): R;
12+
}
13+
}
1114

1215
const dispatchThunkResult: number = dispatch(() => 42);

‎test/typescript/middleware.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
import {
22
Middleware, MiddlewareAPI,
33
applyMiddleware, createStore, Dispatch, Reducer, Action
4-
} from "../../index.d.ts";
4+
} from "../../";
55

6+
declare module "../../" {
7+
export interface Dispatch<S> {
8+
<R>(asyncAction: (dispatch: Dispatch<S>, getState: () => S) => R): R;
9+
}
10+
}
611

7-
type Thunk<S, O> = (dispatch: Dispatch, getState?: () => S) => O;
12+
type Thunk<S, O> = (dispatch: Dispatch<S>, getState?: () => S) => O;
813

914
const thunkMiddleware: Middleware =
1015
<S>({dispatch, getState}: MiddlewareAPI<S>) =>
11-
(next: Dispatch) =>
12-
<A, B>(action: A | Thunk<S, B>): B =>
16+
(next: Dispatch<S>) =>
17+
<A extends Action, B>(action: A | Thunk<S, B>): B|Action =>
1318
typeof action === 'function' ?
1419
(<Thunk<S, B>>action)(dispatch, getState) :
15-
<B>next(<A>action)
20+
next(<A>action)
1621

1722

1823
const loggerMiddleware: Middleware =
1924
<S>({getState}: MiddlewareAPI<S>) =>
20-
(next: Dispatch) =>
25+
(next: Dispatch<S>) =>
2126
(action: any): any => {
2227
console.log('will dispatch', action)
2328

@@ -47,7 +52,7 @@ const storeWithThunkMiddleware = createStore(
4752
);
4853

4954
storeWithThunkMiddleware.dispatch(
50-
(dispatch: Dispatch, getState: () => State) => {
55+
(dispatch: Dispatch<State>, getState: () => State) => {
5156
const todos: string[] = getState().todos;
5257
dispatch({type: 'ADD_TODO'})
5358
}

‎test/typescript/reducers.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
Reducer, Action, combineReducers,
33
ReducersMapObject
4-
} from "../../index.d.ts";
4+
} from "../../";
55

66

77
type TodosState = string[];
@@ -47,8 +47,7 @@ type RootState = {
4747
counter: CounterState;
4848
}
4949

50-
51-
const rootReducer: Reducer<RootState> = combineReducers<RootState>({
50+
const rootReducer: Reducer<RootState> = combineReducers({
5251
todos: todosReducer,
5352
counter: counterReducer,
5453
})

‎test/typescript/store.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
Store, createStore, Reducer, Action, StoreEnhancer,
33
StoreCreator, Unsubscribe
4-
} from "../../index.d.ts";
4+
} from "../../";
55

66

77
type State = {

‎yarn.lock

+4,184
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.