Introduction
Portuguese version: Typescript-eslint + prettier para padronização de código em React com Typescript
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 and 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.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
settings: {
react: {
version: "detect",
},
}
}
);
- tseslint.config: where the typescript-eslint configurations are specified
- eslint.configs.recommended: applies the recommended eslint rules in the code analysis
- tseslint.configs.recommendedTypeChecked: applies the recommended typescript rules in the code analysis, that additionally require type information
- projectService: indicates to ask typescript's type checking service for each source file's type information
- import.meta.dirname: tells the parser the absolute path of project's root directory
- 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 hooks rules:
yarn add eslint-plugin-react eslint-plugin-react-hooks --dev
- eslint-plugin-react: brings linting rules for React
- eslint-plugin-react-hooks: brings hooks rules
Adding the plugins in the eslint configuration file:
- eslint.config.mjs
// @ts-nocheck
import eslint from "@eslint/js";
import reactPlugin from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'],
{
settings: {
react: {
version: "detect",
},
},
plugins: {
"react-hooks": reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
}
}
);
- // @ts-nocheck: Used to ignore the type check for this file due to an issue with eslint-plugin-react-hooks related to missing type declarations
- 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
- plugins: add the eslint-plugin-react-hooks plugin to extend eslint
- rules: add customizable rules, in the case of eslint-plugin-react-hooks, the recommended rules are included
Adding prettier
The lib will be added:
yarn add prettier --dev
A configuration file named .prettierrc
is created at the root, initially empty since the default rules of the library are not being modified.
Customization of rules
At the moment, the configuration of typescript-eslint and prettier has been done, applying the recommended rules from the added plugins and the default from prettier. However, inside a project, some of these rules might be interesting to modify, and this can be done through the eslint and prettier configuration file.
Prettier customization
To customize prettier rules, use the following structure:
{
rule: rule_expectation,
rule: rule_expectation
}
- 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 default 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:
- .prettierrc
{
"singleQuote": true,
"jsxSingleQuote": true
}
Eslint customization
To customize eslint rules, use the following structure:
"rules": {
rule: error_type,
rule: [error_type, rule_expectation]
}
- 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; oroff
, 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, react and react-hooks. 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:
// @ts-nocheck
import eslint from "@eslint/js";
import reactPlugin from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'],
{
settings: {
react: {
version: "detect",
},
},
plugins: {
"react-hooks": reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
"no-console": "warn", // eslint rule
"react/jsx-no-useless-fragment": "error", // React rule
"react-hooks/exhaustive-deps": "off", // hooks rule
"@typescript-eslint/no-unused-vars": "off", // typescript rule
}
}
);
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:
// @ts-nocheck
import eslint from "@eslint/js";
import reactPlugin from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'],
// the rules will not apply to these types of files
{
ignores: ["**/*.stories.tsx"],
},
{
settings: {
react: {
version: "detect",
},
},
plugins: {
"react-hooks": reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
"no-console": "warn",
"react/jsx-no-useless-fragment": "error",
"react-hooks/exhaustive-deps": "off",
"@typescript-eslint/no-unused-vars": "off",
}
}
);
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:
// @ts-nocheck
import eslint from "@eslint/js";
import reactPlugin from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'],
{
ignores: ["**/*.stories.tsx"],
},
{
settings: {
react: {
version: "detect",
},
},
plugins: {
"react-hooks": reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
"no-console": "warn",
"react/jsx-no-useless-fragment": "error",
"react-hooks/exhaustive-deps": "off",
"@typescript-eslint/no-unused-vars": "off",
}
},
// specific files with specific rules for them
{
files: ["**/*.test.tsx"],
rules: {
"@typescript-eslint/no-unused-expressions": "off",
},
}
);
Script package.json
To run eslint and check the application's code, run prettier and check the application's formatting, 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",
"format": "prettier . --check",
"format-fix": "prettier . --write"
"format-src": "prettier src --check",
"format-src-fix": "prettier src --write"
}
- 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
- format: it will check all the application's files formatting, following the rules defined in the prettier configuration file
- format-fix: it will auto-correct the formatting for the entire application, following the rules defined in the prettier configuration file
- format-src: it will check all the files inside the src folder formatting (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 prettier configuration file
- format-src-fix: it will auto-correct the formatting for all the files inside the src folder, following the rules defined in the prettier configuration file
Article updates
Initially, the article had configured typescript-eslint to run together with prettier, it was using tseslint.configs.recommended
instead of tseslint.configs.recommendedTypeChecked
and mentioned that it wasn't possible to use the eslint-plugin-react-hooks
plugin. However, Josh Goldberg, a team member of the linters, pointed out three interesting points that made me update the article:
- the typescript-eslint recommends using tseslint.configs.recommendedTypeChecked for typed-linting
- the typescript-eslint does not recommend running the prettier plugin together with it. An article was shared explaining this better: You Probably Don't Need eslint-config-prettier or eslint-plugin-prettier
- it is possible to use
eslint-plugin-react-hooks
because you can disable the type checking in the eslint configuration file
For this reason, I modified it to use tseslint.configs.recommendedTypeChecked
, separated typescript-eslint from prettier (each with its own responsibility) and added eslint-plugin-react-hooks
.
Conclusion
The idea of this article is to present how to configure typescript-eslint and 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)