Как отобразить релейное (graphql) соединение с узлами ребра, используя обобщенные типы с Typescript - PullRequest
0 голосов
/ 26 сентября 2019

Недавно я экспериментировал с запросами, соответствующими React, GraphQL, Apollo и Relay.Прямо сейчас у меня есть бэкэнд GraphQL, который имеет простую схему graphql с некоторыми запросами Connection для возврата списков сущностей, которые могут быть разбиты на страницы с использованием спецификаций сервера ретрансляции.

На внешнем интерфейсе я повторял себя послевыполнение указанных запросов с помощью кода, который обычно выглядит примерно так:

type isDefined = <T>(value: T | null | undefined): value is T => value !== null && value !== undefined;

export const AppleListComponent: React.FC = () => {
  const { data } = useAppleQuery(); // FWIW, generating this with graphql-code-generator
  const apples = data && data.apples;
  const appleNodes = apples && apples.edges.map(apple => (
    apple ? apple.node : undefined
  )).filter(apple => isDefined(apple));

  return (
    <div>
      {appleNodes && appleNodes.map(apple => (
        <p key={apple.text}>{apple.text}</p>
      ))}
    </div>
  );
};

Необходима песня и танец проверки наличия, так как спецификация Relay требует, чтобы ребра и узлы были Nullable.Я часто повторяю это преобразование из формата реле в простой формат массива узлов.Я решил посмотреть, смогу ли я создать вспомогательную функцию, которая принимает нечто, соответствующее интерфейсу соединения, и возвращает либо неопределенный, либо список сопоставленных узлов.Эта попытка выглядела следующим образом:

type Maybe<T> = T | null;
type isDefined = <T>(value: T | null | undefined): value is T => value !== null && value !== undefined;

type Connection<T> = Maybe<{ edges: Array<Maybe<{ node: Maybe<T> }>>}>;

export const connectionToNodes = <T>(connection: Connection<T>): Maybe<T[]> => (
  connection && connection.edges.map(edge => (
    edge ? edge.node : undefined
  )).filter(isDefined)
);

, которая позволяет предыдущему компоненту стать

export const AppleListComponent: React.FC = () => {
  const { data } = useAppleQuery();
  const apples = data && data.apples;
  const appleNodes = connectionToNodes(apples);

  return (
    <div>
      {appleNodes && appleNodes.map(apple => (
        <p key={apple.text}>{apple.text}</p>
      ))}
    </div>
  );
};

Моя проблема здесь в том, что мой тип для Соединения, конечно, не совсем совпадает с моим типомЯ передаю, у которого есть больше свойств, которые выглядят так:

Maybe<(
  { __typename?: 'AppleConnection' }
  & { edges: Array<Maybe<(
    { __typename?: 'AppleEdge' }
    & { node: Maybe<{ __typename?: 'AppleType' }
      & { __typename?: 'QuestionType' }
        & Pick<QuestionType, 'text'>
    > }
  )>> }
)>

Так что я получаю ошибки о том, что вопрос любого типа, и ошибки, которые я передаю connectionToNodes, не соответствуютуказанный тип.Мой инстинкт заключается в том, что я должен сказать, что мой тип T является подтипом чего-то другого - конечно, для целей приложения мне все равно, является ли это Apple или Pear соединение / ребро / узел, но я бы хотелкак для того, чтобы это было в конечном счете выведено - какой-нибудь совет относительно того, как достигнуть этого?

...