DEV Community

Eduardo Henrique Gris
Eduardo Henrique Gris

Posted on

Typescript-eslint + prettier for code standardization in React with Typescript

Introduction

Last month, I started part 1 of the basis for creating and publishing a React library with Typescript, where I'll be applying content I wrote last year. In the next part, I'll define the code standardization for the library, but instead of using what I wrote last year, which includes two articles with a React-focused approach using eslint with prettier (one on setup and another on rule customization), I'll use typescript-eslint with prettier in the library. For this reason, before moving on to part 2, I'm writing this article on that topic.

Libs

  • typescript-eslint: responsible for analyzing the code to identify and resolve issues
  • prettier: responsible for code formatting

Setup typescript-eslint

To add typescript-eslint:

yarn add typescript-eslint eslint @eslint/js --dev

  • typescript-eslint: allows eslint to parse typescript syntax and provides linting rules for typescript.
  • eslint: dependency required by typescript-eslint
  • @eslint/js: provides eslint rules

Generate a configuration file at the root of the project:

  • eslint.config.mjs
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  {
    settings: {
      react: {
        version: "detect",
      },
    }
  }
);
Enter fullscreen mode Exit fullscreen mode
  • tseslint.config: where the typescript-eslint configurations are specified
  • eslint.configs.recommended: applies the recommended eslint rules in the code analysis
  • tseslint.configs.recommended: applies the recommended typescript rules in the code analysis
  • settings: it is set to detect the version of React being used in the project

Adding plugins

The following libraries will be added to apply React and prettier rules:

yarn add prettier eslint-plugin-prettier eslint-config-prettier eslint-plugin-react --dev

  • prettier: add the library responsible for code formatting
  • eslint-plugin-prettier, eslint-config-prettier: brings prettier rules and allows prettier to run alongside typescript-eslint
  • eslint-plugin-react: brings linting rules for React

Adding the plugins in the eslint configuration file:

  • eslint.config.mjs
import eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import reactPlugin from "eslint-plugin-react";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  reactPlugin.configs.flat.recommended,
  reactPlugin.configs.flat['jsx-runtime'],
  eslintPluginPrettierRecommended,
  {
    settings: {
      react: {
        version: "detect",
      },
    }
  }
);
Enter fullscreen mode Exit fullscreen mode
  • reactPlugin.configs.flat.recommended: applies the recommended React rules in the code analysis
  • reactPlugin.configs.flat['jsx-runtime']: required for React 17+ to work with the new jsx runtime introduced in that version
  • eslintPluginPrettierRecommended: applies the recommended prettier rules for code formatting. It is necessary to place it last in the order to disable eslint rules that conflict with it

Customization of rules

At the moment, the configuration of typescript-eslint with prettier has been done, applying the recommended rules from the added plugins. However, inside a project, some of these rules might be interesting to modify, and this can be done through the eslint configuration file.

Prettier customization

To customize prettier rules, use the following structure:

rules: {
  "prettier/prettier": [
    "error_type",
    {
      rule: rule_expectation,
      rule: rule_expectation
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode
  • prettier/prettier: define that you are customizing a prettier rule
  • error_type: it can be warn, which returns a warning if the rule is not satisfied, or it can be error, which returns an error if the rule is not satisfied
  • rule: corresponds to the rule that will be customized
  • rule_expectation: corresponds to what is expected for the code to follow

At the moment, the eslint configuration file is using the recommended prettier rules, among which are some rules to not use single quotes for code and jsx. Starting from an example where the project wants to define the use of single quotes, it would look like this in the configuration file:

  • eslint.config.mjs
import eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import reactPlugin from "eslint-plugin-react";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  reactPlugin.configs.flat.recommended,
  reactPlugin.configs.flat['jsx-runtime'],
  eslintPluginPrettierRecommended,
  {
    settings: {
      react: {
        version: "detect",
      },
    },
    "rules": {
      "prettier/prettier": [
        "error",
        {
          "singleQuote": true,
          "jsxSingleQuote": true,
        }
      ]
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Eslint customization

To customize eslint rules, use the following structure:

"rules": {
  rule: error_type,
  rule: [error_type, rule_expectation]
}
Enter fullscreen mode Exit fullscreen mode
  • rule: corresponds to the rule that will be customized
  • error_type: it can be warn, which returns a warning if the rule is not satisfied; error, which returns an error if the rule is not satisfied; or off, which disables the rule
  • rule_expectation: corresponds to what is expected for the code to follow

In the case of a rule that already has an expectation defined inside it, rule: error_type is passed directly. For rules that can have multiple expectations, rule: [error_type, rule_expectation] is passed, defining what is expected from it.

At the moment, the eslint configuration file is using the recommended rules from eslint, typescript-eslint and react. Starting from an example where the project wants to define a customizable rule for each of them, it would look like this in the configuration file:

import eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import reactPlugin from "eslint-plugin-react";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  reactPlugin.configs.flat.recommended,
  reactPlugin.configs.flat['jsx-runtime'],
  eslintPluginPrettierRecommended,
  {
    settings: {
      react: {
        version: "detect",
      },
    },
    "rules": {
      "prettier/prettier": [
        "error",
        {
          "singleQuote": true,
          "jsxSingleQuote": true,
        }
      ],
      "no-console": "warn", // eslint rule
      "react/jsx-no-useless-fragment": "error", // React rule
      "@typescript-eslint/no-unused-vars": "off", // typescript rule
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Ignore files

There will be certain types of files for which you don't want the typescript-eslint to run. To do this, you can add ignores in the configuration file. As an example, for an app that ignores documentation files with storybook in the standardization, it would look like this:

import eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import reactPlugin from "eslint-plugin-react";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  reactPlugin.configs.flat.recommended,
  reactPlugin.configs.flat['jsx-runtime'],
  eslintPluginPrettierRecommended,
  // the rules will not apply to these types of files
  {
    ignores: ["**/*.stories.tsx"],
  },
  {
    settings: {
      react: {
        version: "detect",
      },
    },
    "rules": {
      "prettier/prettier": [
        "error",
        {
          "singleQuote": true,
          "jsxSingleQuote": true,
        }
      ],
      "no-console": "warn",
      "react/jsx-no-useless-fragment": "error",
      "@typescript-eslint/no-unused-vars": "off",
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Specific rules for certain types of files

In addition to defining files to exclude from running typescript-eslint, it's also possible to define customizable rules specifically for certain files by setting them alongside files. As an example, for an app that disables a rule for test files, it would look like this:

import eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import reactPlugin from "eslint-plugin-react";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  reactPlugin.configs.flat.recommended,
  reactPlugin.configs.flat['jsx-runtime'],
  eslintPluginPrettierRecommended,
  {
    ignores: ["**/*.stories.tsx"],
  },
  {
    settings: {
      react: {
        version: "detect",
      },
    },
    "rules": {
      "prettier/prettier": [
        "error",
        {
          "singleQuote": true,
          "jsxSingleQuote": true,
        }
      ],
      "no-console": "warn",
      "react/jsx-no-useless-fragment": "error",
      "@typescript-eslint/no-unused-vars": "off",
    }
  },
  // specific files with specific rules for them
  {
    files: ["**/*.test.tsx"],
    rules: {
      "@typescript-eslint/no-unused-expressions": "off",
    },
  }
);
Enter fullscreen mode Exit fullscreen mode

Script package.json

To run eslint and check the application's code, scripts will be added to the package.json:

// ...
"scripts": {
  // ...
  "lint": "eslint .",
  "lint-fix": "eslint . --fix",
  "lint-src": "eslint src",
  "lint-src-fix": "eslint src --fix"
}
Enter fullscreen mode Exit fullscreen mode
  • lint: it will check all the application's files, following the rules defined in the eslint configuration file
  • lint-fix: it will auto-correct the code for the entire application, following the rules defined in the eslint configuration file
  • lint-src: it will check all the files inside the src folder (I used src as an example, but it could be any directory inside the app where these checks are necessary), following the rules defined in the eslint configuration file
  • lint-src-fix: it will auto-correct all the files inside the src folder, following the rules defined in the eslint configuration file

Problem

Unlike the article I wrote about eslint with prettier, it is currently not possible to add the eslint-plugin-react-hooks plugin to typescript-eslint, which brings rules according to the expected hook definitions, due to an issue related to missing type declarations.

Conclusion

The idea of this article is to present how to configure typescript-eslint with prettier, adding plugins, and showing how to customize rules. In part 2 of the component library configuration, this article will be used as a basis to define the code standardization rules.

Top comments (0)