Type error when processing graphql result

162 views Asked by At

I just started playing with reasonML and graphql and have built a simple react component that retrieves data from a world cup API. My code is below:

[@bs.module] external gql: ReasonApolloTypes.gql = "graphql-tag";

module GetMatches = [%graphql
  {|
    query getMatches($id: ID!){
        matches(id: $id) {
            date
            homeTeam {name}
            awayTeam {name}
            homeScore
            awayScore
            goals {
              scorer {
                name
              }
              time
            }
          }
    }
  |}
];

module GetMatchesQuery = ReasonApollo.CreateQuery(GetMatches);

let component = ReasonReact.statelessComponent("Matches");

let make = _children => {
  ...component,
  render: _self => {
    let matchParam = GetMatches.make(~id="300331511", ());
    <GetMatchesQuery variables=matchParam##variables>
      ...{
           ({result}) =>
             switch (result) {
             | Loading => <div> {ReasonReact.string("Loading")} </div>
             | Error(error) =>
               <div> {ReasonReact.string(error##message)} </div>
             | Data(response) => <Matches matches=response##matches />
             }
         }
    </GetMatchesQuery>;
  },
};

Matches Component

let component = ReasonReact.statelessComponent("Matches");

let make = (~matches, _children) => {
  ...component,
  render: _self =>
    <div>
      {
        matches
        |> Js.Array.map(match => <Match match key=match##id />)
        |> ReasonReact.array
      }
    </div>,
};

But I'm getting this error:

This has type:
    option(Js.Array.t(option({. "awayScore": option(int),
                               "awayTeam": option({. "name": option(string)}),
                               "date": option(string),
                               "goals": option(Js.Array.t(option({. "scorer": 
                                                                   option(
                                                                   {. "name": 
                                                                    option(
                                                                    string)}),
                                                                   "time": 
                                                                   option(
                                                                   string)}))),
                               "homeScore": option(int),
                               "homeTeam": option({. "name": option(string)})})))
  But somewhere wanted:
    Js.Array.t(Js.t(({.. id: string} as 'a))) (defined as array(Js.t('a)))

I added Js.log(response##matches); and got this in the console
Js.log

1

There are 1 answers

2
glennsl On

I'm pretty sure there's some context missing here, and that you have something like open Belt at the top of your file.

The type error says response##matches is an array in an option, but also that the array elements themselves are in options, which is super weird. So my theory is that the code generated by graphql-ppx uses something like array indexing, which translates to a call to Array.get that in the standard library throws an exception if out of bounds, but in Belt, and many other standard libraries replacements, returns an option.

This is one of many problems with using ppxs. It generates code not in isolation and can interact weirdly with the rest of your code, and it's not easy to debug.