英文:
Redux createAsyncThunkFromAPI wrapper issue
问题
https://stackblitz.com/edit/react-ts-rkekhf?file=app/redux/asyncThunkFromFetch.ts
我们使用以下助手来创建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!!!
关于这个代码,有一点我不喜欢的是,你不能将零个参数传递给由助手创建的thunk函数。但在我们的情况下,仍然更方便使用它,而不是裸露的@redux/toolkit
中的createAsyncThunk
。
我尝试为payload creator创建默认参数,但没有成功。但我真的不太明白我在做什么。
如何调整createAsyncThunkFromAPI
以从API函数中推断args
?
如何以正确的方式实现相同的想法?
我需要了解哪些知识,才能自己解决这个问题?
英文:
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?
答案1
得分: 1
<ResponseSchema, RequestParams = never>
<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.
你很接近了,只是差一点点。您的 thunk 工厂将通过查看 apiFunction
的类型来推断泛型 ResponseSchema
和 RequestParams
。这个特定的 apiFunction
没有参数,所以 RequestParams
被推断为 unknown
。我们希望确保它被推断为 never
。因此,我们添加一个默认值 RequestParams = never
。这意味着当无法推断出 RequestParams
时不接受任何参数。
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.
还有最后一件要检查的事情,那就是确保当存在必需的参数时它仍然正常工作。我添加了一个额外的示例,确实它完美地工作。当参数丢失时会出现错误,当提供参数时不会出现错误。
英文:
<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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论