使用 react-apollo Query 组件 render prop 时的流程错误

Flow error when using react-apollo Query component render prop

我有以下代码:

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-typed顺便把apollo-client_v2.x.x.js加到我的项目里

如何做一个可复现的例子并研究问题

所以我们在分析这些类型时需要做的第一件事就是去查找 flow-typed repo. I went ahead a copy-pasted the react-apollo typedefs 中的 typedefs 到流中。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;
    ...
}

不幸的是,由于这些链接的极端长度和 Whosebug 对答案长度的限制,我不得不在 中继续我的回答。我想这个答案可以作为如何开始调试问题的解释。

问题的解决

接解释如何制作

的答案

所以看起来 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.

断言所需的类型