@kallinen/thunk-utility
v0.4.1
Published
TypeScript library for creating typed thunks.
Readme
@kallinen/thunk-utility
A strongly typed utility library for creating and using Redux Toolkit thunks with minimal boilerplate. Designed to work especially well with @kallinen/openapi-axios-client.
The library helps you:
- Create typed thunks easily
- Automatically infer payload types
- Map thunk results to slice state with minimal reducer code
Installation
npm install @kallinen/thunk-utilityMethods
apiThunkFor
Creates a typed Redux thunk from an OpenAPI-generated API function.
This function is not a generic thunk wrapper. It is designed to work specifically with
@kallinen/openapi-axios-client, which attaches metadata required for argument splitting.
Requirements
apiThunkFor only works correctly when:
- The API function is generated by
@kallinen/openapi-axios-client - The function contains attached metadata via
__meta.key - Corresponding metadata exists in the thunk factory
apiMetadatamap
What the metadata provides
The metadata defines how a single input object is split into:
params→ path + query parametersbody→ request body
Without metadata, all arguments will be passed as undefined.
Behavior
Given a function call:
apiThunkFor(api.getUser)()Example
// store.ts
export type ThunkState = {
state: RootState
dispatch: AppDispatch
}
// my-reducer.slice.ts
import { createSlice } from '@reduxjs/toolkit'
import { createThunkFactory } from '@kallinen/thunk-utility'
import type { ThunkState } from './my-store'
import { apiMetadata } from './my-api'
// thunk setup along with reducer. Api metadata is optional but essential for apiThunkFor
const { createThunks, apiThunkFor, customApiThunkFor } = createThunkFactory<ThunkState>(apiMetadata)
// Define thunks
export const thunks = createThunks({
// generate thunks from API
simpleThunk: apiThunkFor(api.hello)(),
customThunk: customApiThunkFor(api.hello)<{ customParam: string }>({
body: ({ customParam }, state) => ({ platform: state.myReducer.platform, customParam })
})
fetchUser: async (_: void, { getState, dispatch }) => {
const state = getState()
// Return payload
return {
id: 1,
name: 'Alice',
}
},
}, 'my')
// Define slice
const mySlice = createSlice({
name: 'my',
initialState: {
user: null as { id: number; name: string } | null,
hello: null as HelloDto | null
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(thunks.fetchUser.fulfilled, (state, action) => {
// action.payload is correctly typed
state.user = action.payload
})
// Or use slice helper to map thunks to state
const helper = sliceHelper(builder, thunks)
helper.mapThunksToState('fulfilled', {
fetchUser: 'user',
simpleThunk: 'hello',
customThunk: 'hello',
})
},
})
export const myReducer = mySlice.reducer
