O jeito certo de migrar para TypeScript

Sim, eu sei a ironia de ter falado que você não é pago para migrar tecnologia e agora estou aqui falando sobre migração. Mas existe uma nuance aqui. Como falei no post anterior, não somos pagos para migrar por migrar, mas faz sentido sim migrar de tecnologia quando isso tem um valor claro pra empresa e/ou pros usuário finais.

E uma migração para TypeScript pode fazer sentido pro seu caso, como fez pro nosso na Carta.

Dito isso, começar um projeto do zero em TypeScript não é difícil. Existem diversas referências por aí. Esse não é o objetivo desse post. O objetivo aqui é ensinar você a migrar um projeto em andamento, que esteja usando JavaScript. E lógico, o mais importante é possibilitar uma migração gradual. É inviável para a maioria dos projetos migrar tudo da noite pro dia. Ou seja: todos os arquivos em JavaScript que existem, devem ter que continuar funcionando normalmente.

Um aviso rápido: estou assumindo que você está usando React, Webpack e Jest. Mas se não estiver, as ideias (provavelmente) se aplicam pro seu caso.

Adicionando o TypeScript

O primeiro passo é adicionar o TypeScript como dependência:

yarn add typescript

Crie um arquivo chamado tsconfig.json na raíz do projeto.

Recomendo que você leia a documentação completa do tsconfig.json para saber o que cada parte da configuração significa e poder usar o que mais se adequada ao seu contexto.

De qualquer forma, segue um exemplo de configuração pronta:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "moduleResolution": "node",
    "jsx": "react",
    "sourceMap": true,
    "strict": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "alwaysStrict": true,
    "declaration": false,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

A parte mais importante dessa configuração, e que você deveria seguir, é o "strict": true. Ela força você a usar a tipagem que o TypeScript oferece, ao invés de simplesmente usar TypeScript como se fosse JavaScript - o que não faz o menor sentido.

Alterando o Webpack

Precisamos alterar o Webpack para que ele consiga interpretar os arquivos escritos em TypeScript (.ts e .tsx).

Pra isso, precisamos instalar outra dependência, o ts-loader:

yarn add -D ts-loader

Abra o arquivo de configuração do webpack do seu projeto. Procure pelo trecho que interpreta o código JavaScript. Vai ser alguma coisa parecida com isso:

{
  "rules": [
    {
      "test": /\.jsx?$/,
      "use": "babel-loader",
      "exclude": /node_modules/
    }
  ]
}

Basta agora acrescentar a parte que vai ser responsável por interpretar código TypeScript. Dessa forma:

{
  "rules": [
    {
      "test": /\.jsx?$/,
      "use": "babel-loader",
      "exclude": /node_modules/
    },
    {      "test": /\.tsx?$/,      "use": "ts-loader",      "exclude": /node_modules/    }  ]
}

Procure também por um trecho semelhante a este:

{
  "resolve": {
    "extensions": [".js", ".jsx"]
  }
}

Faça essa mudança:

{
  "resolve": {
    "extensions": [".js", ".jsx", ".ts", ".tsx"]
  }
}

Pronto, agora o Webpack vai conseguir interpretar tanto arquivos em JavaScript quanto em TypeScript. E o melhor: ambos ao mesmo tempo, o que permite uma migração gradual.

Adaptando o Jest

A parte dos testes é fácil. Instale o ts-jest:

yarn add -D ts-jest

Procure por esse trecho de configuração:

{
  "transform": {
    "^.+\\.jsx?$": "babel-jest"
  }
}

E adicione esta linha:

{
  "transform": {
    "^.+\\.jsx?$": "babel-jest",
    "^.+\\.tsx?$": "ts-jest"  }
}

ESLint

Se você pretende usar o TSLint no seu projeto, pense duas vezes, porque ele está deprecado. Na própria página do TSLint é recomendado que usemos o ESLint.

De todos os passos, ironicamente, o ESLint pode ser o mais complicado.

Novamente, pra começar, precisamos instalar algumas dependências:

yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

Procure o arquivo de configuração do ESLint do seu projeto (geralmente .eslintrc ou .eslintrc.js). Ele vai ser parecido com isso:

module.exports = {
  extends: [
    "eslint:recommended",
    "airbnb",
    "plugin:prettier/recommended",
    "prettier/react",
    "prettier/standard",
  ],
  parserOptions: {
    parser: "babel-eslint",
    ecmaFeatures: {
      modules: true,
      jsx: true,
    },
  },
  plugins: ["react", "react-hooks", "prettier"],
};

O que precisamos fazer é adicionar uma seção separada nessa configuração, que sirva apenas para os arquivos TypeScript. Isso pode ser feito dessa forma:

module.exports = {
  extends: [
    "eslint:recommended",
    "airbnb",
    "plugin:prettier/recommended",
    "prettier/react",
    "prettier/standard",
  ],
  parserOptions: {
    parser: "babel-eslint",
    ecmaFeatures: {
      modules: true,
      jsx: true,
    },
  },
  plugins: ["react", "react-hooks", "prettier"],
  overrides: [    {      files: ["src/**/*.ts", "src/**/*.tsx"],      parser: "@typescript-eslint/parser",      plugins: ["@typescript-eslint"],      rules: {        "no-unused-vars": "off",        "@typescript-eslint/ban-types": "error",        "@typescript-eslint/no-explicit-any": "error",        "@typescript-eslint/no-non-null-assertion": "error",      },    },  ],};

E é isso. Agora você tem um projeto que suporta tanto JavaScript, quanto TypeScript. Ao mesmo tempo.

Se o seu gerente tinha um pé atrás com o TypeScript porque ele não queria perder muito tempo com uma possível migração - e te garanto que o seu gerente está certo - mostre pra ele este tutorial.