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",
},
}
}
);
- 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",
},
}
}
);
- 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
}
]
}
- 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 beerror
, 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,
}
]
}
}
);
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 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
}
}
);
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",
}
}
);
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",
},
}
);
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"
}
- 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)