Original

Start with a simple React Component wrapped with the graphql higher order component from React Apollo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React from 'react'
import gql from 'graphql-tag'
import { graphql } from 'react-apollo'

export const HERO_QUERY = gql`
query GetCharacter($episode: Episodi!) {
hero(episode: $episode) {
name
id
friends {
name
id
appearsIn
}
}
}
`

export const withCharacter = graphql(HERO_QUER, {
options: () => ({
variables: { episode: 'JEDI' }
})
})

export const withCharacter(({ data: { loading, hero, error }}) => {
if (loading) {
return <div>Loading</div>
}
if (error) {
return <div>Error</div>
}
return (
<div>
{hero &&
<div>
<h3>{hero.name}</h3>
{hero.friends.map(friend => <h6 key={friend.i}>{friend.name}</h6>}></h6>)}
</div>
}
</div>
)
})

The above code pulls some data from a GraphQL API using a query and includes lifecycle information, such as loading and error information.

With a few minor changes, we can tell TypeScript how to support us in writing code within this render function.

  • We need to tell TS what the shape of our data from our graphql server will look like. We manually write the types for our response data.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export type Hero {
name: string
id: string
appearsIn: string[]
friends: Hero[]
}

export type Response {
hero: Hero
}

export const withCharacter = graphql<Response>(HERO_QUERY, {
options: ({episode}) => ({
variables: { episode }
})
})
  • The last line is where the magic happens. We tell TS what the shape of the result will look like from the server when the graphql enhancer wraps a component.

If you already had your project set up with TS, and have already typed your response data, all you have to do is add the type to the graphql HOC and you are off!

Take Control of Your Tree

Wrapped components are almost always exported and used by a component somewhere else in your tree, so if your exported component has prop requirements, we need to tell TS so it can help prevent errors elsewhere in our tree. Since the graphql wrapper suppors polymorphic types, we can use the second type parameter of it to do just that.

1
2
3
4
5
6
7
8
9
export type InputProps = {
episode: string
}

export const withCharacter = graphql<Response, InputProps>(HERO_QUERY, {
options: ({ episode }) => ({
variables: { episode },
})
})

Then the code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from 'react'
import ApolloClient, { createNetworkInterface } from 'apollo-client'
import { ApolloProvider } from 'react-apollo'

import Character from './Character'

export const networkInterface = createNetworkInterface({
uri: 'https://mpjk0plp9.lp.gql,zone/graphql',
})
export const client = new ApolloClient({
networkInterface,
})
export default () => (
<ApolloProvider client={client}>
<Character />
</ApolloProvider>
)