Last active
September 14, 2017 00:38
-
-
Save quicksnap/33710cb0d3688d9e8d7243ac9331ec17 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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