https://stackblitz.com/edit/react-ts-rkekhf?file=app/redux/asyncThunkFromFetch.ts
We use the following helper to create thunks:
import { createAsyncThunk } from '@reduxjs/toolkit';
import axios, { AxiosPromise, AxiosResponse } from 'axios';
import { store } from './store';
export const createAsyncThunkFromAPI = <ResponseSchema, RequestParams>(
typePrefix: string,
apiFunction: ApiFunction<RequestParams, ResponseSchema>
) => {
return createAsyncThunk<ResponseSchema, RequestParams>(
typePrefix,
async (args, thunkApi) => {
try {
const response = await apiFunction(args);
return response.data;
} catch (e) {
return thunkApi.rejectWithValue(e);
}
}
);
};
type ApiFunction<RequestParams, ResponseSchema> = (
axiosParams: RequestParams
) => AxiosPromise<ResponseSchema>;
export const getMobileOperatorsAPI = (): Promise<AxiosResponse<string[]>> => {
return axios.get('https://api.com');
};
export default createAsyncThunkFromAPI;
const sliceName = 'mobile-operators';
export const fetchMobileOperators = createAsyncThunkFromAPI(
`${sliceName}/fetchMobileOperators`,
getMobileOperatorsAPI
);
store.dispatch(fetchMobileOperators()); //Expected 1 arguments, but got 0.ts(2554)
store.dispatch(fetchMobileOperators({})); //Ouch!!!
One thing I hate about it, you cannot pass zero arguments to a thunk function created by the helper. However in our case it's still more convenient to use it instead of bare createAsyncThunk
from @redux/toolkit
I tried to make a default parameter for payload creator with no success. But I don't really understand what I'm doing here.
How to tweak createAsyncThunkFromAPI
to infer args
from API function?
How to implement the same idea in a proper way?
What knowledge do I miss to be able to resolve this problem by myself?
<ResponseSchema, RequestParams = never>
You are very close and just missing one tiny little thing. Your thunk factory will infer the type for the generics ResponseSchema
and RequestParams
by looking at the types of the apiFunction
. This particular apiFunction
has no argument so the RequestParams
is getting inferred as unknown
. We want to make sure that it gets inferred as never
instead. Therefore we add a default value RequestParams = never
. This means that no args
will be accepted when the RequestParams
cannot be inferred.
export const createAsyncThunkFromAPI = <ResponseSchema, RequestParams = never>(
After making this change, the desired usage has no error and your workaround solution does have an error.
store.dispatch(fetchMobileOperators()); // okay!
store.dispatch(fetchMobileOperators({})); // Expected 0 arguments, but got 1.(2554)
There's one last thing to check which is to make sure that it still works properly when there is a required argument. I added an additional example and sure enough it works perfectly. We get an error when the argument is missing and no error when an argument is provided.