DEV Community

Cover image for How to use Gatsby with Typescript.
Manos Menexis
Manos Menexis

Posted on

How to use Gatsby with Typescript.

Intro

As a JAMstack & React enthusiast one of my favorite SSG - (Static Site Generator) Frameworks is Gatsbyjs.

I have used Gatsbyjs to create my company's website as well as a bunch of other customers' too.

A couple of years ago I started playing around with Typescript and instantly fell in love with it. It helped me write better and more predictable code, while it also provided a level of documentation around my codebase.

While Gatsbyjs supports Typescript out of the box, I found out that there was not enough documentation about their Config Files.

Inside its configuration files, Gatsby provides a rich set of lifecycle APIs to hook into its bootstrap, build, and client runtime operations. They allow sourcing data, creating pages, and customizing generated HTML pages.

In this article we will take a look on how to set up our Gatsby website and support it fully with Typescript.

Initial setup

After generating a Gatsby site with gatsby new, you can immediately rename any file inside of /src from .js to .tsx and it will work out of the box. So that's done. What you will find though is that files like gatsby-browser.js, gatsby-node.js or gatsby-ssr.js wont work out of the box with this method.

Installing packages

Its really useful to install types for react, react-dom, node and probably react-helmet. You can install thouse via npm like so:

npm install @types/node @types/react @types/react-dom @types/react-helmet --save-dev
Enter fullscreen mode Exit fullscreen mode

And we also need ts-node.

npm install ts-node
Enter fullscreen mode Exit fullscreen mode

Then on gatsby-config.js in the beginning of the file add:

// gatsby-config.js

require('ts-node').register({
    compilerOptions: {
        module: 'commonjs',
        target: 'es2017',
    },
})

module.exports = {
// rest of the config
...
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.json

Even though there is a plugin for it, I usually like to add my own tsconfig.json file in the root of my project. My tsconfig.json file looks like this:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "esnext",
    "jsx": "preserve",
    "lib": [
      "dom",
      "es2015",
      "es2017"
    ],
    "strict": true,
    "noEmit": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "resolveJsonModule": true
  },
  "include": [
    "./src/**/*"
  ]
}
Enter fullscreen mode Exit fullscreen mode

The rest of the files

After setting up my tsconfig.json I create a folder inside /src called app. I usually store all my config and provider files there.

For the sake of time i will provide two example files that i use in every project and I am pretty sure you can figure out how to apply it to the rest.

gatsby-node.js - createPages

If you worked with Gatsby before this should look familiar with the only difference being that is written in Typescript.

Let's assume we want to create pages from a list of article we fed into Gatsby's internal graphql.

// src/app/GatsbyNode.tsx

import * as path from "path"
import { GatsbyNode } from "gatsby";

type TypePost = {
  id: string
  title: string
  slug: string
  content: string
}

type TypeData = {
    allPost: {
        nodes: TypePost[]
    }
}

export const createPages: GatsbyNode["createPages"] = async ( { graphql, actions } ) => {

  const { createPage } = actions

  const data = await graphql<TypeData>( `
      {
          allPost {
              nodes {
                  id
                  title
                  slug
                  content
              }
          }
      }
      ` )

  // Create Post Pages  
  const postTemplate = path.resolve("./src/templates/Post.tsx")
  const createPostPromise = data?.allPost.nodes.map((post) => {
      createPage({
          path : `posts/${post.slug}`,
          component : postTemplate,
          context : {
              slug: post.slug,
              // anything else you want to pass to your context
          }
      })
  })

  await Promise.all( [ createPostPromise] )
}
Enter fullscreen mode Exit fullscreen mode

Then on gatsby-node.js we do this:

// gatsby-node.js

'use strict'

exports.onCreatePage = require("./src/app/GatsbyNode").onCreatePages

Enter fullscreen mode Exit fullscreen mode

If you are using multiple apis inside of ./src/app/GatsbyNode.ts
like onCreatePage or onCreateWebpackConfig you can also do:

// gatsby-node.js

'use strict'

module.exports = require("./src/app/GatsbyNode")
Enter fullscreen mode Exit fullscreen mode

This will run all the functions of ./src/app/GatsbyNode.ts, but you have to make sure you export the functions with the correct name based on Gatsby's documentation.

gatsby-browser.js & gatsby-ssr.js - wrapRootElement

So let's assume we also want to add a theme provider to our app. On the src/app/ folder that we created before we add the file WrapRootElement.tsx

// src/app/WrapRootElement.tsx

import React from "react";
import { GatsbyBrowser } from "gatsby";
import { ThemeProvider } from "./ThemeContext";

const wrapRootElement: GatsbyBrowser['wrapRootElement'] = ( { element } ) => {
    return (
        <ThemeProvider>            
            { element }
        </ThemeProvider>
    )
}

export default wrapRootElement
Enter fullscreen mode Exit fullscreen mode

Then on gatsby-browser.js & gatsby-ssr.js files:

// gatsby-browser.js & gatsby-ssr.js

import WrapRootElement from "./src/app/WrapRootElement";

export const wrapRootElement = WrapRootElement
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope this tutorial helps you use Gatsby & Typescript more effectively and save you some time searching how to actually use the config files of Gatsby with Typesript. Thank you for your time!!!

Discussion (0)