Convert Gatsby from JavaScript to TypeScript

By default the code behind a Gatsby site is written in JavaScript. However, as a site scales it can become more difficult to maintain all of that JavaScript. One way to improve the scalability of the site is to migrate from JavaScript to TyepScript.

🚀 TL;DR Show me the code. Look at the 1-typescript branch.

What is TypeScript?

TypeScript is a superset of JavaScript (all JavaScript code is valid TypeScript code). JavaScript is dynamically typed, which means that the type of a variable is determined at runtime. In contrast, TypeScript is statically typed, with the type of variables being determined at compile-time. This help developers rigorously define the type and form of their objects, so that type-related errors can be caught earlier in the development cycle.

Porting from JavaScript to TypeScript

The change from JavaScript to TypeScript should be done incrementally. Make small changes and ensure that nothing breaks with each change.

We’ll use the Gatsby Starter Project discussed in a previous post as the starting point. Clone that repository.

File Types

When you start working with TypeScript you’ll notice that there are two common file extensions: .ts and .tsx. What’s the difference?

  • .ts files contain pure TypeScript and
  • .tsx files can also include JSX content (analogous to .jsx files for JavaScript).

💡 JSX (JavaScript XML) is an extension to JavaScript, primarily used with React. It allows developers to write HTML elements and components using a JavaScript-like syntax.

We’re going to simply rename our JavaScript files, implicitly turning them into TypeScript files.

  1. Go into the src/pages folder and change the extensions on all of the files from .js to .tsx.
  2. Go into the src/components folder. Change the extensions on header.js, layout.js and seo.js to .tsx.

Rebuild the site and take a look. The site should not have changed.

Add Dependencies

Make the following edits to package.json:

  • in the dependencies section add gatsby-plugin-typescript; and
  • in the devDependencies section add @typescript-eslint/eslint-plugin, @typescript-eslint/parser and typescript.

Rebuild the site so that those packages get installed.

Create a Configuration File

We can use the TypeScript Compiler, tsc, to generate a default configuration file.

First spin up a Node environment.

docker run -it -v ${PWD}:/site --entrypoint /bin/bash datawookie/gatsby:latest

Now create a fresh tsconfig.json file.

# Using Node Package eXecute.
npx tsc --init
# Using Yarn.
yarn tsc --init

Most of the file will be commented out. What remains should look something like this:

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

Uncomment the entry for jsx and set the value to "react".

{
  "compilerOptions": {
    "target": "es2016",
    "jsx": "react",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

Implicit Any Type

Try to compile the TypeScript using either of the following commands.

npx tsc
yarn tsc

You will probably get a bunch of TS7031 errors, which arise because variables are implicitly being typed as any. Fix these by assigning explicit types to those variables.

Type Declarations for CSS

Try to compile again. You will get a TS2307 error because TypeScript is looking for type definitions in a CSS file.

We could fix this manually. But it’s easier and more robust to use a package which is designed specifically to deal with it. Install the typed-css-modules package (this is included in the "package.json" file). The package comes with a utility, tcm. Run it using either of the following commands.

npx tcm src -p
yarn tcm src -p

That will find all CSS files under the src folder and create a declaration file (with a .d.ts extension) for each of them.

At this stage all errors should have been resolved and your TypeScript will compile smoothly.

Automating TypeScript Checks

Gatsby won’t check your TypeScript files. But you can run tsc over your code before running gatsby by making a simple update to package.json:

"scripts": {
  "build": "tsc --noEmit && gatsby build",
  "develop": "tsc --noEmit && gatsby develop",
  "start": "tsc --noEmit && gatsby develop"
}

Now if you run yarn build (or yarn develop or yarn start) your TypeScript code will be checked first. The --noEmit flag tells tsc not to produce any JavaScript code.

Conclusion

By enforcing a level of type safety and providing a richer development environment, TypeScript helps to ensure that large-scale projects remain clean, organised, and bug-free, which in turn, enhances productivity and long-term maintainability.

The code for this post can be found here.