使用react-apollo Query组件渲染道具时出现流错误

时间:2018-07-06 18:16:36

标签: flowtype react-apollo apollo-client flow-typed

我有以下代码:

import { Query } from 'react-apollo';

type Post = {
  id: string
};

interface Data {
  posts: Array<Post>;
}

class PostsQuery extends Query<Data> {}

按以下方式使用上述内容时:

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

我从流程中收到以下错误:

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

知道为什么吗?

我确实使用flow-typedapollo-client_v2.x.x.js添加到我的项目中

2 个答案:

答案 0 :(得分:3)

问题解决方案

接续说明如何制作verifiable example and research the problem.

因此看来,react-apollo的这一部分没有以使访问data内容简单明了的方式键入。好的,那很好,我们可以建议他们进行销毁并检查空数据。同时,我们还可以向id类型添加Post属性,以便流程不再抱怨:

({Try-滚动至底部以获取相关代码)

type Post = {
  id: string,
  title: string;
};

...snip...

// Look ma, no errors
class Search extends React.Component<{}> {
  render = () => (
    <PostsQuery query={QUERY}>
    {({ loading, error, data }) => {
      if (error) {
        return <p>Error</p>
      }
      if (loading) return <p>Loading</p>
      const nonNullData = (data || {})
      const dataWithAllPosts = {allPosts: [], ...nonNullData}
      const {allPosts} = dataWithAllPosts
      if (allPosts.length == 0) {
        return <p>Empty response or something</p>
      }
      return (
          <div>
            {allPosts.map(post => {
              return <div key={post.id}>{post.title}</div>;
            })}
          </div>
      );
    }}
    </PostsQuery>
  );
}

我对react-apollo库不熟悉,所以我不确定在没有帖子的情况下如何处理这种情况。我刚刚添加了一条消息,如上所述。这种情况很可能永远不会发生(再次,您会比我更了解)。如果是这种情况,您可能要跳过上述某些步骤,而只需使用cast through any声明所需的类型。

答案 1 :(得分:1)

如何制作可复制的示例并研究问题

因此,在分析这些类型时,我们要做的第一件事是在flow-typed repo中查找typedef。我继续将react-apollo typedefs复制粘贴到flow.org/try,对其进行了稍微修改(在某个地方添加了any,将gql设置为any),并且能够复制错误:

({Try-滚动到代码底部)

参考relevant lines of the QueryRenderProps type,我们可以看到为什么流程抛出错误:

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

看起来数据可以是TData(可能是您想要的),空对象或未定义。与typescript typings for react-apollo进行交叉检查,我们可以看到类型为何如此:

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

不幸的是,由于这些链接的极端长度以及stackoverflow对答案长度的限制,我不得不在another answer中继续我的答案。我想这个答案可以用来解释如何开始调试问题。