如何使Typescript识别Apollo查询的类型

时间:2018-06-15 00:17:25

标签: reactjs typescript apollo react-apollo

我试图让Apollo与TypeScript集成。 我有一个React类,如下所示:

interface Data {
  allVendors: Array<VendorType>;
}

class AllVendorsQuery extends Query<Data> {}

const ShowVendors: React.SFC<> = props => {
  return (
    <AllVendorsQuery query={fetchVendors}>
      {({ loading, error, data: { allVendors } }) => {
        if (loading) {
          return 'Loading...';
        }
        if (error) {
          return `Error! ${error.message}`;
        }

        return (
          allVendors &&
          allVendors.map((vendor, index: number) => {
            return (
              <div key={`${vendor.name}_${index}`}>
                #<strong>{vendor.id}</strong>
                &nbsp;{vendor.name}
              </div>
            );
          })
        );
      }}
    </AllVendorsQuery>
  );
};

export default ShowVendors;

查询是:

export default gql`
  query GetVendors {
    allVendors {
      id
      name
    }
  }
`;

TypeScript抱怨[ts] Type 'Data | undefined' has no property 'allVendors' and no string index signature.出现在这一行:{({ loading, error, data: { allVendors } })

但是,如果我使用apollo-connect而不是Query组件重构代码,我不会从TypeScript中得到任何抱怨:

import { graphql, compose, QueryResult } from 'react-apollo';

interface ShowVendorsProps {
  data: QueryResult & { allVendors?: VendorType[] };
}

class ShowVendors extends React.Component<ShowVendorsProps> {
  render() {
    const {
      data: { allVendors }
    } = this.props;

    if (allVendors && allVendors.length > 0) {
      return (
        <div>
          {allVendors.map((vendor, index: number) => {
            return (
              <div key={`${vendor.name}_${index}`}>
                #<strong>{vendor.id}</strong>
                &nbsp;{vendor.name}
              </div>
            );
          })}
        </div>
      );
    } else {
      return 'Loading';
    }
  }
}

export default compose(graphql(fetchVendors))(ShowVendors);

两者有什么区别?如何重写第一个语句的类型?

2 个答案:

答案 0 :(得分:3)

有一个小的库和一个CLI,可以为服务器(根据您的架构)和客户端(根据您的架构和GraphQL文档)生成TypeScript类型。它还会生成解析器签名并且非常可定制。

您可以在这里尝试:https://github.com/dotansimha/graphql-code-generator

这里有关于该软件包的博客文章; https://medium.com/the-guild/graphql-code-generator-for-typescript-react-apollo-7b225672588f

其背后的想法是允许开发人员充分利用GraphQL和生成的类型,并使自定义生成的输出更容易。

它还可以根据您的需要生成反应阿波罗组件。

答案 1 :(得分:1)

由于您在第一个代码块中使用data解构data: { allVendors },因此TypeScript会抱怨因为data可能未定义,例如数据仍在加载时。

因此,对于TS没有抱怨,您可以在加载检查后进行解构,使用allVendors的默认值,例如:

interface Data {
  allVendors: Array<VendorType>;
}

class AllVendorsQuery extends Query<Data> {}

const ShowVendors: React.SFC<> = props => {
  return (
    <AllVendorsQuery query={fetchVendors}>
      {({ loading, error, data }) => {
        if (loading) {
          return 'Loading...';
        }
        if (error) {
          return `Error! ${error.message}`;
        }

        // If data is not undefined, then it sets allVendors accordingly.
        // Otherwise it sets it to null (which you check for anyways below)             
        const {allVendors} = data || {allVendors: null}; 

        return (
          allVendors &&
          allVendors.map((vendor, index: number) => {
            return (
              <div key={`${vendor.name}_${index}`}>
                #<strong>{vendor.id}</strong>
                &nbsp;{vendor.name}
              </div>
            );
          })
        );
      }}
    </AllVendorsQuery>
  );
};

export default ShowVendors;