CosmicCode

Generating TypeScript typings from GraphQL schema in Gatsby

Created May 5th, 2018

Last updated May 5th, 2018

Gatsby
TypeScript
GraphQL

In this post we learn how to create TypeScript typings from GraphQL schemas and then how to use that in our pages. Gone are the days of creating interfaces for each query

TypeScript makes a massive difference to the modern web development experience and building a website with Gatsby should be no exception. Given that static types are the key to getting the most out of TypeScript and that Gatsby deals with object structures generated from GraphQL queries how do we reconcile the two?

The answer comes from generating TypeScript typings from the GraphQL schema itself.

Previously a basic Gatsby page in TypeScript my have looked like this:

import * as React from 'react'
import Link from 'gatsby-link'

interface NotFoundQuery {
  data: {
    site: {
      siteMetadata: {
        title: string 
      }
    }
  }
}

const NotFoundPage = (query: NotFoundQuery) => (
  <div>
    <h1>Page not found</h1>
    <p>It looks like the page you are looking for does not exist </p>
    <Link to='/'>Return to {query.data.site.siteMetadata.title}</Link>
  </div>
)

export const NotFoundQuery = graphql`
  query NotFoundQuery {
    site {
      siteMetadata {
        title
      }
    }
  }`

Here we have created an interface specifically for the query we are running - but this duplicates the object schema that is already defined in GraphQL. To automate this we are going to use graphql-code-generator

To install:

npm install --save-dev graphql-code-generator
npm install --save-dev graphql-codegen-typescript-template

The first installs the glient while the second installs typescript specific support.

We now have the gql-gen cli installed. We can add a script to this to package.json to streamline the process:

  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "graphql-types": "gql-gen --url http://localhost:8000/___graphql --template typescript --out ./src/graphql-types.d.ts",

The above command will connect to your running Gatsby instance's GraphQL server to access the schema and will output the typings in the source directory.

This does mean however that we need to run this while the server is running so make sure that gatsby develop has been run first. Ensure that you re-run this each time one of your plugin sources has changed object schema.

Our above code can now be implemented as:

import * as React from 'react'
import Link from 'gatsby-link'
import { RootQueryType } from '../graphql-types';

const NotFoundPage = (query: {data: RootQueryType}) => (
  <div>
    <h1>Page not found</h1>
    <p>It looks like the page you are looking for does not exist </p>
    <Link to='/'>Return to {query.data.site ? query.data.site.siteMetadata ? query.data.site.siteMetadata.title : '' : ''}</Link>
  </div>
)

export const NotFoundQuery = graphql`
  query NotFoundQuery {
    site {
      siteMetadata {
        title
      }
    }
  }`

export default NotFoundPage

It is also worth noting that the types cover the entire schema and will not match exactly what has been received in the query response. For this reason most fields are optional meaning that they can be null. This will simply mean that it forces you to null check each field.

This has saved me a lot of time writing additional interfaces and in VS Code helps with the autocompletion over the query objects.

Andrew

Web development enthusiast with a keen interest in anything frontend.