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

Posted

技术标签:

【中文标题】如何让 Typescript 识别 Apollo 查询的类型【英文标题】:How to make Typescript recognize the type for an Apollo Query 【发布时间】:2018-11-24 19:52:38 【问题描述】:

我正在尝试让 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);

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

【问题讨论】:

【参考方案1】:

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

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

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

其背后的想法是让开发人员充分利用 GraphQL 和生成的类型,并更轻松地自定义生成的输出。

它还可以生成带有您需要的类型的 react-apollo 组件。

【讨论】:

【参考方案2】:

由于您在第一个代码块中使用data: allVendors 解构data,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;

【讨论】:

以上是关于如何让 Typescript 识别 Apollo 查询的类型的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Apollo 工具为查询生成 Typescript 类型,包括 Apollo @client 和 @rest 指令?

如何在 TypeScript 中使用 Apollo Client 自定义钩子?

如何使用 apollo 客户端从 schema.graphql 中提取 typescript 接口:codegen

使用 react-apollo,如何使用 TypeScript 在同一个组件中定义 2 个突变?

如何在 TypeScript 中为 React Apollo Query 组件编写 HOC?

如何在 Firestore Cloud Functions 上使用 Apollo Server GraphQL 在 TypeScript 中处理身份验证