in my react project I declare my api requests with this pattern:
export type LoginApiResponse = {
token: string,
user: User
}
export function login(email: string, password: string): Promise<LoginApiResponse> {
return AuthService.signinWithEmailAndPassword(email, password)
}
and I consume them through a custom hook
export function useApi<T, Fn extends (...args: any[]) => Promise<T>>(
fn: Fn
) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const execute = async (...params: Parameters<Fn>) => {
setLoading(true);
try {
const result = await fn(...params);
setLoading(false);
return result;
} catch (err) {
console.warn("sideEfect execution error", err, JSON.stringify(err));
setError(err);
setLoading(false);
throw (error);
}
};
return { loading, execute, error };
}
with an implementation like this
const loginExecutor = useApi<LoginApiResponse, typeof api.login>(api.login)
In this way I encapsulate loading and error state for a given api request, plus I have full typing support
THE QUESTION
Now my question is: is there a way to take advantage of typescript type inference to infer the return type and parameters type of the fn function in order to be able to write
useApi(api.login)
instead of
useApi<LoginApiResponse, typeof api.login>(api.login)
While keeping the same strong typing?
I see that your example infers everything except a response. It has the following type:
const loginExecutor = useApi(login)
const loginExecutor: {
loading: boolean;
execute: (email: string, password: string) => Promise<unknown>;
error: string;
}
Try on TS Playground
I updated useApi
to extract args and return type separarly:
export function useApi<A extends any[], T>(
fn: (...args: A) => Promise<T>
)
So now we get following type:
const loginExecutor = useApi(login)
const loginExecutor: {
loading: boolean;
execute: (email: string, password: string) => Promise<LoginApiResponse>;
error: string;
}
Try on TS Playground
Please note that my examples were tested on TS >= 4.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.