Search code examples
flowtypereact-apolloapollo-clientflow-typed

Flow error when using react-apollo Query component render prop


I have the following code:

import { Query } from 'react-apollo';

type Post = {
  id: string
};

interface Data {
  posts: Array<Post>;
}

class PostsQuery extends Query<Data> {}

When using the above as follows:

<PostsQuery query={POSTS_QUERY}>
  {({ loading, data }) => {
    ...
    {data.posts.map(...)}
    ...
  }
</PostsQuery>

I get the following error from flow:

Error:(151, 27) Cannot get 'data.posts' because property 'posts' is missing in object type [1].

Any idea why?

I did use flow-typed to add apollo-client_v2.x.x.js to my project by the way


Solution

  • How to make a reproducible example and research the problem

    So the first thing we need to do while analyzing these types is to go lookup the typedefs in the flow-typed repo. I went ahead a copy-pasted the react-apollo typedefs into flow.org/try, modified them slightly (added an any somewhere, set gql to any), and was able to replicate your errors:

    (Try - Scroll to the bottom for your code)

    Referencing the relevant lines of the QueryRenderProps type, we can see why flow is throwing the error:

    {
         data: TData | {||} | void,
         ...
    }
    

    It looks like data can either be TData (probably what you want), an empty object, or undefined. Cross checking this with the typescript typings for react-apollo, we can see why the type is the way it is:

    {
        ...
        // we create an empty object to make checking for data
        // easier for consumers (i.e. instead of data && data.user
        // you can just check data.user) this also makes destructring
        // easier (i.e. { data: { user } })
        // however, this isn't realy possible with TypeScript that
        // I'm aware of. So intead we enforce checking for data
        // like so result.data!.user. This tells TS to use TData
        // XXX is there a better way to do this?
        data: TData | undefined;
        ...
    }
    

    Unfortunately, due to the extreme length of these links and stackoverflow's limit on answer lengths, I have to continue my answer in another answer. I guess this answer can serve as an explanation of how to start debugging the problem.