Eli Weinstock-Herman

Swapping tslint for eslint w/ react-scripts 3.0.0

May 14, 2019 ▪ technical posts

react-scripts 3.0.0 has shifted TypeScript linting support from tslint to eslint (release notes). This is on the general roadmap for TypeScript in general, so while eslint doesn't support all of the rules I'm using w/ tslint at the moment, it's good enough that I want to try a full migration.

Why lint at all?

I like using linters in real-time because they push me to move past working code to learn best practices and the ins and outs of a language. This way I don't end up writing language A in the style of language B and I have shared conventions with my teammates that let me read and understand the codebase more quickly.

I've had a love/hate relationship with tslint. It was especially helpful with TypeScript, since I could have simply written everything in JavaScript and thrown a .ts[x] extension on it. Unfortunately, the integration with my current editor of choice (vs code) was less than wonderful. Between only linting files that I have opened and an occasional crash, once I upgraded my skill to a certain point I wouldn't realize it had crashed for days.

Migrating TypeScript linting to eslint

Having used eslint with a similar configuration for a week now, I can tell that I'm not getting the same level of linting support that I did with tslint (when tslint was working). There are rules I expect to see that are not showing up (such as conventions on import order), while some new ones have popped up.

You can run tslint side-by-side with the eslint support added by react-scripts 3.0.0, so if you're migrating to 3.0.0 I would suggest doing it in two stages:

  1. Migrate to 3.0.0, commit and lock in the work
  2. Try a full conversion and see if it works for your team yet

Migrate to 3.0.0

Follow the instructions to migrate to 3.0.0. Get this good and working with your codebase, make sure your Jest tests work, etc. Then lock in these changes with a commit so you can also verify they're working in CI, etc.

At this point, I had to clean up a number of new syntax and compilation errors in the code before moving on to the linter change.

Then and only then, try full eslint migration

Now that you have your existing codebase working with 3.0.0, now you can follow along and experiment with a full conversion. Once you get this done, it could be useful to look at some changes side-by-side with a teammate to see what you gain and lose (don't forget to also run your CI commands, to see if you get the same results).

Setting up eslint

Some of the steps may duplicate work the react-scripts migration provided, if so just let me know in the comments. react-scripts is a bit of a black box to me, but hasn't made it high enough on my list yet to really dig into (though I've been regularly running into friction that's getting me closer to investing the time).

Add TypeScript parser and plugin

From typescript-eslint I installed the parser and plugin:

npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin

Then I added the recommended rules and prettier, attempting to match the base set of rules I was using with tslint:

.eslintrc.json

{
  "extends": [
    "react-app",
    "plugin:@typescript-eslint/recommended",
    "prettier",
    "prettier/@typescript-eslint"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "parserOptions": {
    "project": "./tsconfig.json"
  }
}

One sample file worth of warnings

Note: In the sample application, I also had to install eslint-config-react-app. This is a dependency of react-scripts and did not require explicit installation on my production app, but eslint complained about it locally on the sample app. There is a github issue for an earlier version of react-scripts, but the team closed it as they didn't personally see a need to run the linter seperately from the CRA scripts 🤷‍

Run the whole project in vs code

I'm applying a new-ish set of rules to an existing project, so I'd like to see the results from all of my files. The vs code extension only runs files you open, but rather than switching to the command-line output (which is not terrible, but...) I found a vs code setting that adds a task that will run eslint across all files in the project in one shot:

.vscode/settings

{
    // ...
    "eslint.provideLintTask": true
    // ...
}

Note: Unfortunately, this task did not work with the sample project - for some reason the extension could only find a global installation of eslint and was unable to work with my local one on this machine (even after removing the global one).

npm tasks

Next up is updating the npm tasks to use eslint. I have two lint tasks, one for local command-line usage and one for CI:

package.json

{
    // ...
    "lint": "node ./node_modules/eslint/bin/eslint.js --config .eslintrc.json --ext .js,.ts,.tsx src",
    "lint-ci": "node ./node_modules/eslint/bin/eslint.js --config .eslintrc.json --ext .js,.ts,.tsx --format node_modules/eslint-teamcity/index.js src",
    // ...

Command-line results

This runs eslint for *.js, *.ts, and *.tsx files in my src directory only (yes, I have accidentally linted node_modules on far more than a couple occasions). My lint-ci command also includes a formatter for my particular build server (TeamCity), which provides better visibility and formatting in CI then raw console output.

fin

My project is now running eslint instead of tslint. I get eslint output live in vs code, further customized some of the rules, and get good feedback in CI as well. I've noticed a number of tslint rules, for instance on ordering of imports and which types of quotes to use, are no longer showing up. I can't tell yet whether I've gained an equal number of different rules or lost value in the trade.

If you've made the switch, I'd love to hear about it and anything you've found that adds good rules in (or if I missed a step).

There's a sample project with the migration at . Here are the relevant commits:

Share: