#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, это инструмент, который может создавать все интерфейсы, необходимые для ваших запросов.