Introdução
English version: Typescript-eslint + prettier for code standardization in React with Typescript
No mês passado comecei a parte 1 da base de criação e publicação de uma lib React com Typescript, onde vou aplicar para a lib conteúdos que escrevi no ano passado. Na próxima parte, vou definir a parte de padronização de código nela, mas ao invés de usar o que escrevi ano passado, que foram dois artigos com visão React usando eslint com prettier (um de setup e um de customização de regras), vou usar typescript-eslint e prettier na lib. Por esse motivo antes de seguir para a parte 2, estou escrevendo esse artigo com esse tema.
Libs
- typescript-eslint: responsável por analisar o código na busca e solução de problemas
- prettier: responsável pela formatação de código
Setup typescript-eslint
Para adicionar o typescript-eslint:
yarn add typescript-eslint eslint @eslint/js --dev
- typescript-eslint: permite o eslint fazer parse de sintaxe typescript, traz regras de linting para typescript
- eslint: dependência que o typescript-eslint necessita
- @eslint/js: traz regras do eslint
Gerar arquivo de configuração na raiz do projeto:
- 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: onde é passada as configurações do typescript-eslint
- eslint.configs.recommended: aplica as regras recomendadas do eslint na análise do código
- tseslint.configs.recommendedTypeChecked: aplica as regras recomendadas do typescript na análise do código, permitindo linting com informação de types
- projectService: melhora a performance ao compartilhar um único serviço de análise de tipos para múltiplos arquivos
- import.meta.dirname: indica a raiz do projeto para o parser
- settings: está definido para detectar a versão de React que está sendo usada no projeto
Adição plugins
Serão adicionados as seguintes libs para aplicar as regras do React e hooks:
yarn add eslint-plugin-react eslint-plugin-react-hooks --dev
- eslint-plugin-react: traz regras de linting para React
- eslint-plugin-react-hooks: traz regras dos hooks
Adição dos plugin no arquivo de configuração do eslint:
- 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: usado para ignorar o check de types desse arquivo, devido a uma issue do
eslint-plugin-react-hooks
referente a estar sem declaração de types. - reactPlugin.configs.flat.recommended: aplica as regras recomendadas do React na análise do código
- reactPlugin.configs.flat['jsx-runtime']: necessário para React 17+, para funcionar com o novo jsx runtime que veio a partir dessa versão
- plugins: adiciona o plugin do eslint-plugin-react-hooks para extender o eslint
- rules: adiciona regras customizáveis, no caso do eslint-plugin-react-hooks é passada as recomendadas lá dentro
Adição prettier
Será adicionada a lib:
yarn add prettier --dev
E criado um arquivo de config na raiz chamado .prettierrc
, a princípio vazio por não ser modificada as regras default da lib.
Customização de regras
No momento foi realizada a configuração do typescript-eslint e prettier, aplicando as regras recomendadas dos plugins adicionados e seguindo com as default do prettier, mas dentro de um projeto parte dessas regras pode ser interessante modificar, isso é possível a partir do arquivo de configuração do eslint e prettier.
Customização prettier
Para customizar as regras do prettier, segue a seguinte estrutura:
{
regra: expectativa_de_regra,
regra: expectativa_de_regra
}
- regra: corresponde a regra que vai ser customizada
- expectativa_de_regra: corresponde ao que é esperado para o código seguir
No momento, no arquivo de configuração do prettier está sendo usada as regras default do prettier, dentre elas estão algumas para não usar aspas simples para o código e jsx. Partindo de um exemplo em que no projeto se quer definir para usar as aspas simples, ficaria da seguinte forma no arquivo de configuração:
- .prettierrc
{
"singleQuote": true,
"jsxSingleQuote": true
}
Customização eslint
Para customizar as regras do eslint, segue a seguinte estrutura:
"rules": {
regra: tipo_de_erro,
regra: [tipo_de_erro, expectativa_de_regra]
}
- regra: corresponde a regra que vai ser customizada
- tipo_de_erro: pode ser
warn
que retorna um aviso se a regra não for satisfeita, ou pode sererror
que retorna erro se a regra não for satisfeita, ou pode seroff
que desabilita a regra - expectativa_de_regra: corresponde ao que é esperado para o código seguir
No caso de ser uma regra que já tem uma expectativa na definição nela, se é passado diretamente regra: tipo_de_erro
, no caso de ser uma regra que pode ter mais de uma expectativa, se é passado regra: [tipo_de_erro, expectativa_de_regra]
definindo o que se espera dela.
No momento, no arquivo de configuração do eslint está sendo usada as regras recomendadas do eslint, typescript-eslint, react e react-hooks. Partindo de um exemplo em que no projeto se quer definir uma regra customizável para cada uma delas, ficaria da seguinte forma no arquivo de configuração:
// @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", // regra eslint
"react/jsx-no-useless-fragment": "error", // regra React
"react-hooks/exhaustive-deps": "off", // regra hooks
"@typescript-eslint/no-unused-vars": "off", // regra typescript
}
}
);
Ignorar arquivos
Terão alguns tipos de arquivos que não se deseja que rode o typescript-eslint, para isso é possível adicionar ignores
no arquivo de configuração. Passando como exemplo de uma app que ignora arquivo de documentação com storybook na padronização:
// @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'],
// as regras não se aplicarão para esses tipos de arquivo
{
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",
}
}
);
Regras específicas para alguns tipos de arquivos
Além de definir arquivos para não rodar o typescript-eslint, é possível também definir regrar customizáveis específicas para arquivos específicos a partir da definição junto de files
. Partindo como exemplo de uma app que cancela uma regra para arquivos de teste:
// @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",
}
},
// arquivos específicos com regras específicas para eles
{
files: ["**/*.test.tsx"],
rules: {
"@typescript-eslint/no-unused-expressions": "off",
},
}
);
Script package.json
Para executar o eslint e verificar o código da aplicação, executar o prettier e verificar a formatação da aplicação, serão adicionados scripts no 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: vai verificar todos os arquivos da aplicação, seguindo as regras definidas no arquivo de configuração do eslint
- lint-fix: vai autocorrigir o código de toda a aplicação, seguindo as regras definidas no arquivo de configuração do eslint
- lint-src: vai verificar todos os arquivos dentro da pasta src (usei src como exemplo, mas seria onde for importante dentro da app fazer essas verificações), seguindo as regras definidas no arquivo de configuração do eslint
- lint-src-fix: vai autocorrigir todos os arquivos dentro da pasta src, seguindo as regras definidas no arquivo de configuração do eslint
- format: vai verificar a formatação de todos os arquivos da aplicação, seguindo as regras do prettier
- format-fix: vai autocorrigir a formatação de todos os arquivos da aplicação, seguindo as regras do prettier
- format-src: vai verificar a formatação de todos os arquivos dentro da pasta src (usei src como exemplo, mas seria onde for importante dentro da app fazer essas verificações), seguindo as regras do prettier
- format-src-fix: vai autocorrigir a formatação de todos os arquivos dentro da pasta src (usei src como exemplo, mas seria onde for importante dentro da app fazer essas verificações), seguindo as regras do prettier
Atualização artigo
A princípio o artigo tinha configurado o typescript-eslint para rodar em conjunto com o prettier, estava usando o tseslint.configs.recommended
ao invés de tseslint.configs.recommendedTypeChecked
e dizia que não era possível usar o plugin eslint-plugin-react-hooks
.
Mas Josh Goldberg, que é um team member dos linters, me passou três pontos interessantes que me fizeram atualizar o artigo:
- o typescript-eslint recomenda usar tseslint.configs.recommendedTypeChecked: typed-linting
- o typescript-eslint não recomenda executar o plugin do prettier em conjunto com ele, passou um artigo explicando melhor sobre: You Probably Don't Need eslint-config-prettier or eslint-plugin-prettier
- é possível usar o
eslint-plugin-react-hooks
, pois é possível tirar a verificação da typagem no arquivo de config do eslint
Por esse motivo, modifiquei para usar o tseslint.configs.recommendedTypeChecked
, separei o typescript-eslint do prettier (cada um com sua responsabilidade) e adicionei o eslint-plugin-react-hooks
.
Conclusão
A ideia desse artigo é apresentar como configurar o typescript-eslint e o prettier, adicionando plugins e mostrando como customizar regras. Na parte 2 da configuração da lib de componentes, será utilizado esse artigo como base e definido as regras de padronização de código.
Top comments (0)