Skip to content

Instantly share code, notes, and snippets.

@seansean11
Last active January 25, 2023 19:03
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save seansean11/196c436988c1fdf4b22cde308c492fe5 to your computer and use it in GitHub Desktop.
Save seansean11/196c436988c1fdf4b22cde308c492fe5 to your computer and use it in GitHub Desktop.
Using Redux Thunk with Typescript (example)
import { ActionCreator } from 'redux'
import { ThunkAction } from 'redux-thunk'
import { WebService } from 'app/services/WebService'
// Create this reusable type that can be imported into your redux action files
export type ThunkResult<R> = ThunkAction<R, RootState, Services, RootAction>
// Services are only necesarry because we are using
// `reduxThunk.withExtraArgument({ webService }))` when we are creating our store.
export type Services = {
webService: WebService
}
// Union type of all of your actions
export type RootAction = UserAction
// Interface of your root Redux state
export interface RootState {
readonly user: UserState
}
// Enum of your action types
export enum ActionType {
UserUpdate = 'USER_UPDATE',
}
export interface UserAction {
readonly type: ActionType
readonly user: Partial<UserState>
}
export interface UserState {
readonly groups: Array<string>
readonly isLoading: boolean
}
import {
Thunk,
ActionType,
UserAction,
UserState,
} from './storeTypes'
export const updateUser = (user: Partial<UserState>): UserAction => ({
type: ActionType.UserUpdate,
user
})
// ***** USING THUNKRESULT TYPE HERE ***** //
// this ThunkResult is `void` because it doesn't return anything
// if you return something from the thunk, replace `void` with the return value `ThunkResult<void>`
export const login = (email: string, password: string): ThunkResult<void> => async (
dispatch,
getState,
{ webService }
) => {
try {
const { jwt, groups } = await webService.signIn(
email,
password
)
webService.setBearerToken(jwt)
dispatch(updateUser({ groups }))
} catch (err) {
throw err
}
}
@samjmck
Copy link

samjmck commented Jan 6, 2019

I can't dispatch this from the main store, there is a type error about the Thunk not having the type property. Do you know how I would go about fixing this?

@seansean11
Copy link
Author

seansean11 commented Feb 12, 2019

@samjmckenzie could you post the full error? Also, what do your types look like? This example only shows the Thunk type being used with my user actions, so I'm wondering if you made modifications or are running this code, as is.

@n3rd253
Copy link

n3rd253 commented Apr 23, 2019

@seansean11 How do you register all of this with your store? Can you provide an example?

@seansean11
Copy link
Author

seansean11 commented Apr 23, 2019

@n3rd253 I'm using a buildStore function from a separate file:

export const buildStore = (initState = initialState): Store<RootState> => {
  const store = createStore(
    rootReducer,
    initState,
    applyMiddleware(reduxThunk.withExtraArgument({ webService }))
  )
  return store
}

export default buildStore()

Store type is defined in the redux library and RootState from the store-types up above.

@n3rd253
Copy link

n3rd253 commented Apr 24, 2019

@seansean11 Thanks mate!

I've followed your typing patterns above and in addition your mark above about withExtraArgument, however when run, i'm still seeing:

FetchCategories.tsx:9 Uncaught (in promise) TypeError: Cannot read property 'getCategories' of undefined
at _callee2$ (FetchCategories.tsx:9)
at tryCatch (runtime.js:45)
at Generator.invoke [as _invoke] (runtime.js:271)
at Generator.prototype.(:9999/anonymous function) [as next] (http://localhost:9999/bundle.js:744:21)
at asyncGeneratorStep (asyncToGenerator.js:3)
at _next (asyncToGenerator.js:25)
at asyncToGenerator.js:32
at new Promise ()
at asyncToGenerator.js:21
at FetchCategories.tsx:7

Hopefully you'll be willing to help me find my typing miss?

@seansean11
Copy link
Author

seansean11 commented Apr 24, 2019

@n3rd253 that isn't a TS compile error, that is a JavaScript error. It's just trying to tell you that on line 9 of your FetchCategories.tsx file, you are calling someObject.getCategories, where someObject (whatever it happens to be called in your codebase) is actually undefined.

@n3rd253
Copy link

n3rd253 commented Apr 24, 2019 via email

@seansean11
Copy link
Author

seansean11 commented Apr 24, 2019

@n3rd253 your issue is unrelated to this Gist. I would check that you are importing your service correctly where you are using it and make sure it is exported correctly from the module where it is defined. Not sure how much I can help you there.

@n3rd253
Copy link

n3rd253 commented Apr 26, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment