https://redux-toolkit.js.org/usage/usage-with-typescript
https://redux-toolkit.js.org/usage/usage-with-typescript#typing-async-thunks-inside-createslice
A type for state and/or dispatch cannot be provided as part of the ThunkApiConfig, as this would cause circular types.
const state = thunkApi.getState() as RootState;
const dispatch = thunkApi.dispatch as AppDispatch;
import { asyncThunkCreator, buildCreateSlice } from '@reduxjs/toolkit';
import { AppDispatch } from './store';
type State = {
title: string;
infoMessages: Array<string>;
open: boolean;
onClose: () => void;
disableActions?: boolean;
};
const noop = () => {};
const initialState: State = {
infoMessages: [],
open: false,
onClose: noop,
title: '',
disableActions: false,
};
const createSliceWithThunks = buildCreateSlice({
creators: { asyncThunk: asyncThunkCreator },
});
export const infoDialogSlice = createSliceWithThunks({
initialState,
name: 'infoDialog',
reducers: (create) => ({
closeInfoDialog: create.reducer(() => {
return {
open: false,
infoMessages: [],
onClose: noop,
title: '',
disableActions: false,
};
}),
openInfoDialog: create.asyncThunk<
Omit<StatewithOptionalOnClose, 'open'>,
State
>(
(payload, thunkApi): State => {
const dispatch = thunkApi.dispatch as AppDispatch;
const {
infoMessages,
onClose = () => dispatch(closeInfoDialog()),
title,
disableActions = false,
} = payload;
return { open: true, infoMessages, onClose, title, disableActions };
},
{
fulfilled: (_, action) => {
return action.payload;
},
}
),
}),
});
// State with optional "onClose" property
type StatewithOptionalOnClose = Omit<State, 'onClose'> &
Partial<Pick<State, 'onClose'>>;
export const { openInfoDialog, closeInfoDialog } = infoDialogSlice.actions;
import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { AppDispatch } from './store';
type State = {
title: string;
infoMessages: Array<string>;
open: boolean;
onClose: () => void;
disableActions?: boolean;
};
const noop = () => {};
const initialState: State = {
infoMessages: [],
open: false,
onClose: noop,
title: '',
disableActions: false,
};
export const infoDialogSlice = createSlice({
initialState,
name: 'infoDialog',
reducers: {
openInfoDialog: (_, action: PayloadAction<Omit<State, 'open'>>) => {
const {
infoMessages,
onClose,
title,
disableActions = false,
} = action.payload;
return { open: true, infoMessages, onClose, title, disableActions };
},
closeInfoDialog: () => {
return {
open: false,
infoMessages: [],
onClose: noop,
title: '',
disableActions: false,
};
},
},
extraReducers: (builder) => {
builder.addCase(
openInfoDialog.fulfilled,
(_, action: PayloadAction<State>) => {
return action.payload;
}
);
},
});
// State with optional "onClose" property
type StatewithOptionalOnClose = Omit<State, 'onClose'> &
Partial<Pick<State, 'onClose'>>;
export const openInfoDialog = createAsyncThunk<
State,
Omit<StatewithOptionalOnClose, 'open'>,
{ dispatch: AppDispatch }
>('infoDialog/openInfoDialog', (payload, { dispatch }) => {
const {
infoMessages,
onClose = () => dispatch(closeInfoDialog()),
title,
disableActions = false,
} = payload;
return { open: true, infoMessages, onClose, title, disableActions };
});
export const { closeInfoDialog } = infoDialogSlice.actions;