не удается найти правильный интерфейс typescript для запроса GraphQL в React с Apollo

#reactjs #typescript #graphql #apollo

#reactjs #typescript #graphql #apollo

Вопрос:

приведенный ниже код представляет собой компонент react, который возвращает таблицу, каждая строка которой представляет собой данные, извлеченные из внутреннего API через GraphQL. Данные извлекаются правильно, но я не могу найти правильный интерфейс для данных, извлекаемых Query компонентом.

Я получаю следующие ошибки:

 TypeScript error: Type '({ data: { allTeams }, error, loading }: SectionTableQueryProps) => Element' is not assignable to type '((result: QueryResult<any, OperationVariables>) => ReactNode) | (((result: QueryResult<any, OperationVariables>) => ReactNode) amp; string) | (((result: QueryResult<any, OperationVariables>) => ReactNode) amp; number) | ... 4 more ... | (((result: QueryResult<...>) => ReactNode) amp; ReactPortal)'.
  Type '({ data: { allTeams }, error, loading }: SectionTableQueryProps) => Element' is not assignable to type '(result: QueryResult<any, OperationVariables>) => ReactNode'.
    Types of parameters '__0' and 'result' are incompatible.
      Property 'allTeams' is missing in type 'QueryResult<any, OperationVariables>' but required in type 'SectionTableQueryProps'.  TS2322

    50 |     <tbody>
    51 |       <Query query={GET_ALL_TEAMS}>
  > 52 |       {({ data: { allTeams = [] } = {}, error, loading }: SectionTableQueryProps) => {
       |       ^
    53 |         if (loading) {
    54 |           return <div>LOADING</div>
    55 |         };   




TypeScript error: Property 'data' does not exist on type 'SectionTableQueryProps'.  TS2339

    50 |     <tbody>
    51 |       <Query query={GET_ALL_TEAMS}>
  > 52 |       {({ data: { allTeams = [] } = {}, error, loading }: SectionTableQueryProps) => {
       |           ^
    53 |         if (loading) {
    54 |           return <div>LOADING</div>
    55 |         };
 

 import React from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import { ApolloError } from 'apollo-client';


interface Team {
  id: string;
  name: string;
}

interface Data {
  allTeams?: Team[];
}

interface SectionTableQueryProps {
    allTeams: Team[];
    error?: ApolloError;
    loading: boolean;
}

const GET_ALL_TEAMS = gql`
  query {
    allTeams {
      id
      name
    }
  }
`;

const SectionTable = (props) => (
  <table className="table table-hover table-responsive">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Actions</th>
      </tr>
    </thead>
    <tbody>
      <Query query={GET_ALL_TEAMS}>
      {({ data: { allTeams = [] } = {}, error, loading }: SectionTableQueryProps) => {
        if (loading) {
          return <div>LOADING</div>
        };
        if (error !== undefined) {
          return <div>ERROR</div>
        };
        return (
          // jsx code of the component
        );
      }}
    </Query>
    </tbody>
  </table>
)

export default SectionTable;
 

Как мне правильно написать свои интерфейсы Typescript?

Ответ №1:

Во-первых, в вашем интерфейсе SectionTableQueryProps вы должны иметь data вместо allTeams , потому <Query> что компонент ожидает, что это значение будет там.

Ошибка TypeScript: свойство ‘data’ не существует для типа ‘sectiontable_queryprops’. TS2339

Но все же, я считаю, что это не решит полностью вашу проблему. Чтобы иметь возможность достичь этого, вам нужно будет создать пользовательский Query компонент, который расширяет apollo query компонент и присваивает им типы.

Что-то вроде:

 interface Team {
  id: string;
  name: string;
}

interface AllTeams {
    allTeams: Team[];
}

const GET_ALL_TEAMS = gql`
  query {
    allTeams {
      id
      name
    }
  }
`;

class MyQuery extends Query<AllTeams> {}

const SectionTable = (props) => (
  <table className="table table-hover table-responsive">
    <tbody>
      {* HERE: we use the custom query component *}
      <MyQuery query={GET_ALL_TEAMS}>
      {({ data, error, loading }) => {
        if (loading) {
          return <div>LOADING</div>
        };
        if (error !== undefined) {
          return <div>ERROR</div>
        };

        // HERE: You have access to the typed interface
        console.log(data.allTeams);

        return (
          // jsx code of the component
        );
      }}
      </MyQuery>
    </tbody>
  </table>
)
 

В противном случае вы могли бы заглянуть в apollo client: codegen, это инструмент, который может создавать все интерфейсы, необходимые для ваших запросов.