Skip to content

Instantly share code, notes, and snippets.

@flushentitypacket
Created January 20, 2018 19:38
Show Gist options
  • Save flushentitypacket/13983b0c20c5b0f832d68ae9b5e9585d to your computer and use it in GitHub Desktop.
Save flushentitypacket/13983b0c20c5b0f832d68ae9b5e9585d to your computer and use it in GitHub Desktop.
Typescript Redux todo combination feature
// store/todo/addTodo.ts
import {Reducer} from 'redux'
import {Action} from 'store/redux' // our fancy new generic type!
interface Todo {
id: number
text: string
completed: boolean
}
const ADD = 'todo/ADD'
interface AddTodoActionPayload extends Todo {}
interface AddTodoAction extends Action<typeof ADD, AddTodoActionPayload> {}
let nextTodoId = 0
const addTodo = (text: string): AddTodoAction => ({
type: ADD,
payload: {
id: nextTodoId++,
text,
completed: false,
},
})
const TOGGLE = 'todo/TOGGLE'
interface ToggleTodoActionPayload {
id: number
}
interface ToggleTodoAction extends Action<typeof TOGGLE, ToggleTodoActionPayload> {}
const toggleTodo = (id: string): ToggleTodoAction => ({
type: TOGGLE,
payload: {
id: nextTodoId++,
},
})
export const actions = {
addTodo,
toggleTodo,
}
export type State = Todo[]
const initialState: State = []
type Actions =
AddTodoAction |
ToggleTodoAction
export const reducer: Reducer<State> = (state: State = initialState, action: Actions): State => {
switch (action.type) {
case ADD:
// thanks to discriminated union types, Typescript knows that `action.payload` is a Todo
return [
...state,
action.payload,
]
case TOGGLE:
// and again, Typescript knows that `action.payload` has the `id` prop here
return state.reduce((resultState: State, todo) => {
if (action.payload.id === todo.id) {
return [...resultState, {
...todo,
completed: !todo.completed,
}]
}
return resultState
}, [])
default:
return state
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment