I'm currently working on a project where I have an api module that contains the types and return types for all of the endspoints I use in the application. I'm seeing myself repeating a lot of logic when fetching data from my api, which is why I though of making a react-hook to make this a bit easier.
I'm thinking the first parameter should be the function to call, and the next one an array of arguments to pass to this function. Since the arguments each api function takes are different, I would love to infer the type of the arguments, based on the function passed as the first parameter. I would also love for the data that I return from the hook, to correspond to what function has been called.
For example if the endpoint returns Promise<User>, I would like the data to be of type User.
This is a minimal example of what I'm trying to accomplish, and it's in no working state since I've been messing around trying to get the typings to work.
How I imagine it to be working
function App() {
const user = useApi(api.getUser, "123");
if (user.loading) return <p>Loading...</p>;
if (user.error) return <p>{user.error}</p>;
return (
<div className="App">
<h1>Hello {user.data.name}</h1>
</div>
);
}
API
type User = {
name: string;
age: number;
};
function getUser(userId: string): Promise<User> {
return Promise.resolve({ name: "Peter", age: 20 });
}
function getFamilyMembers(userId: string): Promise<User[]> {
return Promise.resolve([
{ name: "Jackie", age: 17 },
{ name: "John", age: 42 }
]);
}
useApi-hook
const useApi = (apiCall: keyof typeof api, arguments: any[]) => {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState("");
const [data, setData] = React.useState();
React.useEffect(() => {
// Fetch data from api and set state
apiCall(...arguments)
.then(res => setData(res))
.catch(err => setError("Something bad happened :("))
.finally(() => setLoading(false));
}, []);
return {
loading,
error,
data
};
};
I also created the minimal example on codesandbox