by Francesco Agnoletto

How to setup NextJS with TypeScript and ESLint + prettier

The best tools for full stack development with NextJS

Official NextJS logo

Sharing code on front-end and back-end has always been my dream. NextJS makes it easy with a simple framework including both, simple to run, simple to use.

NextJS makes it really easy to modify its setup, making compatibility a first class citizen.

To jumpstart a NextJS project you don’t need anything more than this command.

$ npm init next-app nextjs-example

Change nextjs-example to whatever name you want the project to have.

$ cd nextjs-example to get in the folder, and now we’re ready to start.

NextJS and TypeScript

NextJS comes with TypeScript just one click away, creates an empty tsconfig.json file and run $ npm run dev.
The tsconfig will be populated automatically and all .js files are ready to be converted to .ts.

Differently from the babel TypeScript presets (used by Gatsby, for example), NextJS will not compile on type errors. I don’t feel a great difference between the two options. At the end of the day, if you are using TypeScript you want your types to be correct, regardless of compilation.

NextJS + prettier

Adding prettier is easily achieved as well.

$ npm i - prettier

And next, create a .prettierrc file.

// .prettierrc
{
  "endOfLine": "lf",
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "es5"
}

And that’s pretty much it.

NextJS + ESLint

ESLint needs to be configured with both TypeScript and prettier, but also NextJS’s React implementation.

There are quite a few libraries that need to be added for this all to work properly.

npm i -D eslint eslint-loader eslint-plugin-react eslint-config-prettier eslint-plugin-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser

A basic .eslintrc.js config will look like this.

// .eslintrc.js
module.exports = {
  // Specifies the ESLint parser
  parser: "@typescript-eslint/parser",
  extends: [
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier/@typescript-eslint",
    "plugin:prettier/recommended",
  ],
  settings: {
    react: {
      version: "detect",
    },
  },
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  plugins: ["@typescript-eslint", "react", "prettier"],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    // Allows for the parsing of modern ECMAScript features
    ecmaVersion: 2018,
    // Allows for the use of imports
    sourceType: "module",
  },
  rules: {
    // Disable prop-types as we use TypeScript for type checking
    "react/prop-types": "off",
    "@typescript-eslint/explicit-function-return-type": "off",
    "prettier/prettier": "error",
    "@typescript-eslint/interface-name-prefix": "off",
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/ban-ts-ignore": "off",
    // needed for NextJS's jsx without react import
    "react/react-in-jsx-scope": "off",
  },
  globals: { React: "writable" },
};

I’m not a fan of an overpersonalized linting config. It takes time away from development and introduces complexity to an accepted standard.

BONUS: NextJS and Jest

Testing makes apps more reliable and bug fixing easier. I prefer to have it and write tests as the app progresses.

Interviews go a lot better when you display testing skills. Being on the other side of the interview, I always appreciate candidates who can write tests.

Jest is the go-to testing library for React applications, adding it to a NextJS application is not too difficult but requires some changes.

First, the packages. jest, @testing-library/jest-dom and @testing-library/react for testing, and babel-jest for the config.

npm i -D jest @testing-library/jest-dom @testing-library/react babel-jest

We need to create a .babelrc file to enable the testing environment.

// .babelrc
{
  "presets": ["next/babel"]
}

The Jest config is pretty short as well, I removed the .css transformations since NextJS includes a good css-in-js solution to handle styles.

// jest.config.js
module.exports = {
  collectCoverageFrom: ["**/*.{ts,tsx}", "!**/*.d.ts", "!**/node_modules/**"],
  // we need to create this file
  setupFilesAfterEnv: ["<rootDir>/setupTests.js"],
  testPathIgnorePatterns: ["/node_modules/", "/.next/",],
  transform: {
    "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
  },
  transformIgnorePatterns: ["/node_modules/"],
};

Last, the setup file for Jest is just one line.

// setupTests.js 
import "@testing-library/jest-dom/extend-expect";

BONUS 2: What about end-to-end tests?

It takes even less time to set up end-to-end testing, I wrote a small how-to here.


If you have any questions, feel free to leave a comment.