Skip to content

Instantly share code, notes, and snippets.

@quicksnap
Last active September 14, 2017 00:38
Show Gist options
  • Save quicksnap/33710cb0d3688d9e8d7243ac9331ec17 to your computer and use it in GitHub Desktop.
Save quicksnap/33710cb0d3688d9e8d7243ac9331ec17 to your computer and use it in GitHub Desktop.
import { Action, createStore } from 'redux';
type PuppyPayload = {
payload: {
timestamp: Date,
numberOfPuppies: number,
}
}
// Action "constant"
const PUPPY_BOMB = actionType<PuppyPayload>('actions/PUPPY_BOMB');
// Action creator
const initPuppyBomb = (howManyPuppies: number) => actionCreator(PUPPY_BOMB)({
// This is typed, and will error if doesn't match `ActionShape`
payload: {
timestamp: new Date(),
numberOfPuppies: howManyPuppies,
}
});
// Dispatch action
const store = createStore(appReducer);
store.dispatch(initPuppyBomb(9001));
// Reducer
type AppState = {
totalBombs: number,
lastBombTime: Date,
}
function appReducer(state: AppState, action: Action): AppState {
// Here, typeof action === Action, so all we know is action.type.
// const foo = action.payload; // Type error!
if (isAction(action, PUPPY_BOMB)) {
// Typeguard: typeof action === PuppyPayload & Action
return {
...state,
totalBombs: state.totalBombs + action.payload.numberOfPuppies,
lastBombTime: action.payload.timestamp,
}
}
// ... rest of reducer
return state;
}
/**
* Implementation
*/
type BoxedActionType<In, Out> = { type: string; };
function isAction<In, Out>(action: any, boxedType: BoxedActionType<In, Out>): action is Out {
return action.type === boxedType.type;
}
function actionType<In, Out = Action & In>(type: string): BoxedActionType<In, Out> {
return { type };
}
function actionCreator<In, Out>(boxedType: BoxedActionType<In, Out>) {
return (partialAction: In) => ({
type: boxedType.type,
...partialAction as any,
} as Action & In);
}
/**
* Advanced - when middleware modifies your actions
*/
type PuppyPayloadOut = {
foo: 'bar',
}
// Action "constant"
const PUPPY_BOMB_ADV = actionType<PuppyPayload, PuppyPayloadOut>('actions/PUPPY_BOMB_ADV');
function appReducer2(state: AppState, action: Action): AppState {
if (isAction(action, PUPPY_BOMB_ADV)) {
const foo = action.foo;
// action.payload -- type error!
}
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment