Reputation:
In my code, I am running a graphql query using a hook that is automatically generated by Codegen. Codegen also generates return types and all data types. Now according to the types generated by codegen, the return type of my data should be LoadUsersQueryResult
. However, while I try to process data using this type, I face certain issues.
So to begin with, I am looking for a way to check whether the returned data is really of this type or not? Something like
if(typeof(data)== LoadUsersQueryResult)
This doesn't work since
'LoadUsersQueryResult' only refers to a type, but is being used as a value here.
According to this answer:
Typescript: Check "typeof" against custom type
the only possible way to do so is to compare with strings instead of the whole type. However, I cannot do that since the returned object will be an object and it could be a completely different object everytime. Are there other possible solutions to it? For example, the return type of my query is supposed to be LoadUsersLazyQueryHookResult. Now I try this:
const [userListData, setUserListData] = useState<LoadUsersLazyQueryHookResult>();```
After running the graphql query, I use ```onCompleted``` to set the data. ```
onCompleted: (data) => {
setUserListData(data);
}
However, I get an error that:
Argument of type 'LoadUsersQuery' is not assignable to parameter of type 'SetStateAction<[(options?: QueryLazyOptions<Exact<{ where?: UserFilter | null | undefined; }>> | undefined) => void, QueryResult<LoadUsersQuery, Exact<...>>] | undefined>'.
Type 'LoadUsersQuery' is not assignable to type '(prevState: [(options?: QueryLazyOptions<Exact<{ where?: UserFilter | null | undefined; }>> | undefined) => void, QueryResult<LoadUsersQuery, Exact<...>>] | undefined) => [...] | undefined'.
Type 'LoadUsersQuery' provides no match for the signature '(prevState: [(options?: QueryLazyOptions<Exact<{ where?: UserFilter | null | undefined; }>> | undefined) => void, QueryResult<LoadUsersQuery, Exact<...>>] | undefined): [...] | undefined'.
This is weird because I did something similar in another project and it worked. Maybe I made a mistake while setting up codegen.
Edit:
const [loadUsers, { data, error }] = useLoadUsersLazyQuery();
...
<button onClick={() => loadUsers()}>CHECK</button>
...
{data && <UsersFoundList data={data} />}
...
// type UsersFoundListProps = {
// data: LoadUsersLazyQueryHookResult
// };
Upvotes: 1
Views: 1530
Reputation: 7666
To build on top of my comment: You are using Apollo Client incorrectly. Let me first show you how you are supposed to use Apollo Client in your case and then explain what actually goes wrong in your code. First, forget everything you know about loading data from a server (e.g. via REST). No componentDidMount
, no setState
etc. If you want you data to be available directly after mount use the useQuery
hook. You have setup codegen and codegen can also generate query specific hooks for you if you want.
function MyComponent(props) {
const { data, loading, error } = useQuery<LoadUsersQueryHookResult>(LoadUsersQuery);
// now either loading == true, error != undefined or data contains you user data
// nothing else required
// Alternatively, use the generated hook. It already has the right return type
const { data, loading, error } useLoadUsersQuery();
}
In very rare cases you want to use a lazy query. For example when you only need the data after a user clicked on a button:
function MyComponent(props) {
const [loadQuery, { data, loading, error }] =
useLazyQuery<LoadUsersQueryHookResult>(LoadUsersQuery);
return (
<>
<button onCLick={() => loadQuery()}>Load data</button>
{Boolean(data) ? (
<div>Here is stringified data: {JSON.stringify(data)}</div>
) : (
<div>Still loading or waiting for user to click the button</div>
)}
</>
)
}
Now one could argue that this doesn't answer the question, but I think that the problem araises from the fact that the generated type is used in a position where it should not be used. You are trying to setup a React state of the type LoadUsersLazyQueryHookResult
. This type is the return type of the useLazyQuery
hook I used in the second example. If we look at it in the Apollo Docs we see that it returns an Array of two elements, the first one being a function and the second one being a complicated object.
And now you are trying to assing the actual query response object to this React state that expects an array. This leads to the type error above.
Upvotes: 1
Reputation: 31
If I understood your question correctly, you're concerned with checking type in runtime (as opposed to static type checking handled by Typescript). You don't have to worry about it at all because one of the things GraphQL does for you is validating data returned by your server resolver against a schema you've defined (CodeGen uses same schema to generate Typescript types for static checking). So if you've defined your schema correctly, you should always end up with one of the 2 outcomes:
Server returns valid data that fits your schema.
Server is unable to return valid data and instead returns response containing error that you might want to handle somehow, but that's completely different story.
Upvotes: 0