Skip to content

Instantly share code, notes, and snippets.

@jahredhope
Last active August 7, 2019 13:44
Show Gist options
  • Save jahredhope/7186d19417da34a09eb397ecc0dbd603 to your computer and use it in GitHub Desktop.
Save jahredhope/7186d19417da34a09eb397ecc0dbd603 to your computer and use it in GitHub Desktop.
Example Redux Reducer file with TypeScript types
/**
* An example redux reducer file
* To be imported into a centralized file, typically using combineReducers.
*
* This pattern focuses on type safety with minimal re-declaring of types.
*
* Format of a file:
* - Actions Types
* - Actions
* - State
* - Initial State
* - Reducer
* - Actions
*
*/
// Import Bound Types
// TypedAction is union of all basic actions
// In addition TypedThunkAction will allow functions that will
// be passed a typed version of dispatch and getState
import { TypedAction, TypedThunkAction } from '../store';
// Create action types
// Typically exported for use in unit tests and other reducers
export enum ActionType {
FOO = 'FOO',
BAR = 'BAR',
}
// Declare the format of the state
interface State {
value: number;
}
// Declare an initial state
const initialState: State = {
value: 0,
};
// Declare and export Actions for this reducer
// Import this in **../store.ts** and add to TypedActions
export type Action =
| {
type: ActionType.FOO;
payload: number;
}
| {
type: ActionType.BAR;
};
// Create a reducer to handle actions
// Use TypedAction for the second parameter, and return State
// Import this in **../store.ts** and add to combineReducers
// Declaring the return type of 'State' is not necessary here, but it helps with type errors
export default (state = initialState, action: TypedAction): State => {
switch (action.type) {
case ActionType.FOO:
return {
value: action.payload,
};
case ActionType.BAR:
return {
value: 0,
};
default:
return state;
}
};
// Export Action Creators
export const syncActionCreator = (value: number): TypedAction => {
return {
type: ActionType.FOO,
payload: value,
};
};
export const asyncActionCreator = (id: number): TypedThunkAction => async (
dispatch,
getState,
) => {
const { example } = getState();
if (example.value !== 0) {
await fetch('example').then(res => {
dispatch({
type: ActionType.BAR,
});
});
}
};
import { combineReducers, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import example, { Action as ExampleAction } from './example/example';
const rootReducer = combineReducers({
example,
});
export default rootReducer;
export type StoreState = ReturnType<typeof rootReducer>;
export type TypedGetState = () => StoreState;
export type TypedAction = ExampleAction;
export type TypedDispatch = Dispatch<TypedAction>;
export type TypedThunkAction = ThunkAction<void, StoreState, null, TypedAction>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment