DEV Community

Eduardo Henrique Gris
Eduardo Henrique Gris

Posted on • Edited on

1

Typescript-eslint + prettier para padronização de código em React com Typescript

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",
      },
    }
  }
);
Enter fullscreen mode Exit fullscreen mode
  • 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,
    }
  }
);
Enter fullscreen mode Exit fullscreen mode
  • // @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
}
Enter fullscreen mode Exit fullscreen mode
  • 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
}
Enter fullscreen mode Exit fullscreen mode

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]
}
Enter fullscreen mode Exit fullscreen mode
  • 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 ser error que retorna erro se a regra não for satisfeita, ou pode ser off 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
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

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",
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

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",
    },
  }
);
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode
  • 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:

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.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs