简体   繁体   中英

check typeof graphql returned data

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
// };

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 (eg 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.

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:

  1. Server returns valid data that fits your schema.

  2. 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.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM