I have the following custom hook called useFocusRefetchQuery
type Props = Parameters<typeof useQuery>;
const useFocusRefetchQuery = (...params: Props) => {
const useQueryResults = useQuery(params);
useFocusEffect(
React.useCallback(() => {
useQueryResults.refetch();
}, [useQueryResults])
);
return useQueryResults;
};
Which I then call in useGetArticle
like this:
export const useGetArticle = (articleId: string) => {
return useFocusRefetchQuery(['getArticle', { articleId }], () => getArticle(articleId), { staleTime: 0 });
};
And useGetArticle
is called like this
const { data: article, isLoading } = useGetArticle('home');
My problem is that in this case, article has a type of unknown
and I can't figure out why is this happening. My guess is that I have to somehow type what is being returned by useFocusRefetchQuery. Before I implemented the custom hook, Typescript automatically inferred the return type of useQuery
CodePudding user response:
I don't recall typescript infering anything from the GQL request string, in my experience you need to provide useQuery
the expected output and input (variables) types as mentioned here in details. The useQuery
signature is as follow:
useQuery<TData = any, TVariables = OperationVariables>
In your case you would have to add both Props
and your article type, say Article
:
import { gql, QueryHookOptions, useQuery } from '@apollo/client';
const GET_ARTICLE_QUERY = gql`
query getArticle {
article: {
id,
articleId,
articleName,
}
}
`
interface ArticleContent {
__typename: "Article";
id: string;
articleId: string;
articleName: string;
}
interface Article {
article: ArticleContent | null;
}
interface ArticleInput {
articleId: string;
}
const useArticleQuery = (options: QueryHookOptions = {}) => {
return useQuery<Article, ArticleInput>(GET_ARTICLE_QUERY);
}
I think its also a good idea to keep the options (QueryHookOptions
) in here so you can use your hook in different contexts.
You can use a tool like Graphql code generator to automatically generate the static types Article
and ArticleInput
for you (based on your schema and your JS gql
requests).
If you want to have a generic hook for several useQuery
that all look the same (for example they all use useFocusEffect
), you will have to do something like this:
function useFocusRefetchQuery<TData, TVariables>(){
const useQueryResults = useQuery<TData, TVariables>();
// ...
}
This way you can use useFocusRefetchQuery
instead of useQuery
, but I really think you will have to pass both the input/output types, which means in the previous example you would have:
const useArticleQuery = (options: QueryHookOptions = {}) => {
return useFocusRefetchQuery<Article, ArticleInput>(GET_ARTICLE_QUERY);
}