TSLint is deprecated: how to upgrade to ESlint

Photo by Sergi Kabrera on Unsplash

I recently upgraded my production typescript project from TSLint to ESLint. Here are the steps and and why I migrated manually.

TSLint end of life

Ts lint is deprecated now. It still works totally fine, but if you want to stay current in your next typescript project you should use ESlint. If you have an existing code base using TsLint you should upgrade as soon as possible.

The primary benefit of moving to Eslint is that you get continuous updates from the team. The eslint-plugin-typescript is under active development.

A secondary benefit is that you also get access to the excellent plugin ecosystem that already exists for ESLint. These will provide you with safety around security and enforce modern JavaScript and TypeScript standards for your team. You can see my list of favorite ESLint plugins here.

Upgrading takes some time but it's not too difficult. The rules are slightly different between the two tools so you will see new errors and warnings when you initially change to ESlint. But they can all be turned off while you upgrade the code to match the rule at your own pace.

Here are the steps I take to upgrade any Typescript project from TSLint to Eslint.

The steps to migrate from TSLint to ESlint

These are the steps we will perform to migrate from TsLint to ESlint

  1. Ensure ESLint is installed
  2. Create an .eslintrc.js config
  3. Add an .eslintignore (optional)
  4. You have to remove the tslint.json file
  5. Update your package.json scripts to use ESLint instead of tslint
  6. Install or activate the ESLint plugin for your IDE
  7. Refactor your code to pass the new rules or temporarily disable rules

A note on the tslint to eslint migration tool

There is an awesome tool available to migrate your tslint configuration directly to an eslint configuration. I found that the output of the tool was very verbose. Depending on your tslint configuration it could be worth trying once. You can always revert the change if the migration tool doesn't produce a useful eslint configuration for you.

To run the migration tool use

npx tslint-to-eslint-config

You will see that the file is very verbose. I took note of the rules the tool identified as problematic for my code but I reverted this change and dealt with the new errors and warnings manually myself.

1. Installing ESLint and rules

ESlint rules are provided in packages called plugins.

Based on the output of the migration tool above you will know what plugins to install so lets add ESLint and all of the rules we need.

These are the absolute minimum plugin packages that I needed on a fairly standard TypeScript project. You can see that I also add the ESLint typescript parser here. This is very important because ESLint needs to understand typescript.

yarn add -D eslint eslint-plugin-import eslint-plugin-prefer-arrow eslint-plugin-unicorn @typescript-eslint/parser @typescript-eslint/eslint-plugin

//or
// npm i --save-dev eslint eslint-plugin-import eslint-plugin-prefer-arrow eslint-plugin-unicorn @typescript-eslint/parser @typescript-eslint/eslint-plugin

A note on the typescript parser

Eslint is built to parse JavaScript into an abstract syntax tree (AST). This is called estree. Eslint doesn't understand TypeScript code like enum or types. The typescript eslint parser will convert our typescript into an estree compatible format so we can pass it to ESlint and the ESlint plugins that are built for JavaScript.

2. Create an ESLint configuration file

First, it's a good idea to be very specific about what files you want to lint. You can achieve this by passing the typescript parser in ESLint a specific tsconfig file describing just that.

I recommend creating a tsconfig.eslint.json file that is based off your primary tsconfig.json but only specifying the files you want to lint. For example you might want to ignore test data files or similar.

{
  // extend your base config to share compilerOptions, etc
  "extends": "./tsconfig.json",
  "compilerOptions": {
    // ensure that nobody can accidentally use this config for a build
    "noEmit": true
  },
  "include": [
    // whatever paths you intend to lint
    "src/**/*.ts"
  ]
}

Next you will need to add the actual ESLint configuration file.

The file should be called .eslintrc.js.

Here is a decent starting point for the plugins we installed above. You can add "the-rule":"off" in the rules section of the configuration to turn off a rule called the-rule. For rules that are in a plugin you would provide the plugin path "plugin/the-rule: "off".

I change the configuration for one rule below to allow file name casing that I like to use on my projects. Each Eslint rule may have configuration options. You have to go to the plugin package's documentation page to find out the allowed configuration.

module.exports = {
  env: {
    es6: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:unicorn/recommended",
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: ["tsconfig.eslint.json"],
    // Allows for the parsing of modern ECMAScript features if you're using modern node.js or frontend bundling
    // this will be inferred from tsconfig if left commented
    // ecmaVersion: 2020,
    sourceType: "module", // Allows for the use of imports
    // Allows for the parsing of JSX if you are linting React
    // ecmaFeatures: {
    //  jsx: true
    // }
  },
  rules: {
    "unicorn/filename-case": [
      "warn",
      {
        cases: {
          camelCase: true,
          pascalCase: true,
        },
      },
    ],
  },
  plugins: ["@typescript-eslint", "import", "prefer-arrow", "unicorn"],
};

A note on prettier

If you use prettier (and you should!) you should install the prettier overrides for ESLint. These overrides remove conflicting rules from interfering with prettier. Eslint should be used to find code issues and leave all stylistic issues to prettier.

To do this install the prettier plugin for eslint.

yarn add -D eslint-config-prettier

//or
// npm i --save-dev eslint-config-prettier

and add the prettier overrides to the end of your list of extensions.

{
  "extends": [
    //... all the other plugin configurations you use,
    "prettier",
    "prettier/@typescript-eslint",
    "prettier/standard",
    "prettier/unicorn"
  ]
}

3. Ignoring files while linting

You might want to ignore some files when linting. Do this using the .eslintignore file. You can add globs like

**/node_modules
node_modules

Please note that the above is just an example and node_modules is already ignored by Eslint.

4. Remove tslint

You can disable the TSLint plugin on your IDE workspace if you use one.

Then remove tslint packages and any plugin packages from the project.json. e.g.

yarn remove -D tslint tslint-consistent-codestyle tslint-eslint-rules tslint-microsoft-contrib

Also remove any scripts referencing tslint in your package.json scripts section.

Finally remove the tslint.json configuration file. You won't need that anymore.

5. Update your lint scripts to run eslint

You can update your lint command in package.json to enable linting with ESLint

"scripts": {
"lint": "npx eslint \"{src,apps,libs,test}/**/*.ts\" -c .eslintrc.js}

and then run

yarn lint

// or
// npm run lint

It's very unlikely that your project will lint with no errors right away. Especially if you're upgrading!

The ESlint rules we just configured are stricter than regular tslint and there are more active rules running on your code now.

You can remove rulesets or disable individual rules as required to give yourself time to upgrade your code.

6. Turning on the ESlint IDE plugin

if you use VSCode you should install the ESLint plugin.

If you use WebStorm you can enable ESLint in the IDE settings.

7. Refactor your code to pass all rules

Now comes the difficult part. You must refactor your code to pass all the rules. Eslint rules often provide fixes for the issues they find. You might want to try this out by running yarn lint --fix

If there are still issues you can fix them manually or temporarily disable the ESlint rule and fix the issues over time.

Conclusion

Upgrading from TSLint to ESLint is a bit painful because you will have to review heaps of rules. Tslint is completely deprecated now so you should consider upgrading if you can.

There are much more comprehensive rule sets available for ESLint and there seems to be better support in IDEs for the ESLint also.

Let me know if you have an issues by using my Twitter!