Lately we started a new project at work, written in React + Typescript. Of course, like any other project we wanted it to be automatically linted and style checked, so we don’t have to worry about that ourselves.
The two largest, most familiar tools for Typescript linting are TSLint and ESLint. While ESLint exists for a longer period, it never had proper, production ready support for Typescript, so most Typescript projects were written with TSLint.
I was tasked with finding the right tool for our project. It is a completely new project, so no code migration or rule migration is necessary. First I looked at TSLint. It has great support for TypeScript, plus an excellent VSCode extension. It definitely seemed like the right choice, until I stumbled upon this article. I found it quite interesting, but If you don’t feel like reading, I’ll give you the gist here.
On Microsoft’s TypeScript roadmap for the first 6 months of 2019 they provide an entire section about the growing demand among Typescript developers to have proper ESLint support. Furthermore, they talk about how ESLint’s architecture is more suitable to their needs, and finally they say they intend to fully embrace ESLint as the linting tool for the Typescript project, and guarantee to improve ESLint’s Typescript support in an effort to match TSLint’s support.
The rest of the article talks about a new repository that aims to contain the core projects needed for ESLint to be able to parse and lint Typescript code.
After some further testing and comparisons, I believe that ESLint is in fact the right tool for the job (not only because I trust the Typescript’s team 😉).
Update - May 10th:
Create React App v3 started linting TypeScript projects with @typescript/eslint as well, so I firmly believe I've made the right choice.
Wow, this was a long introduction. Let’s get coding!
First things first, we need to create a new project. For this article I’ll be using create-react-app
, but whichever boilerplate you choose (or create on your own) will do just fine.
npx create-react-app eslint-react-intro --typescript
For those who are not familiar, npx
is a tool first introduced with node@5.2.0
. In a sentence, it allows us to run binaries of npm packages with ease without global installation. It actually does a little more than that, you’re encouraged to read more in this great article.
Now we have a basic react app, but we’re here for the linting, so let’s install a few dependencies:
npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
eslint
is an obvious dependency, but what are @typescript-eslint/parser
and @typescript-eslint/eslint-plugin
?
ESLint by default depends on a parser to read Javascript code and “translate” it to a language ESLint can understand (also called ESTree
). By default ESLint uses Espree, which is great for reading JS code, but fails to read Typescript. @typescript-eslint/parser
is an alternative parser that can read Typescript code and produce said ESTree, so we can tell ESLint to use it instead. @typescript-eslint/eslint-plugin
is simply a list of rules you can turn on or off.
So we have our basic dependencies, lets configure ESLint.
ESLint has a nice interactive tool that you can run:
eslint --init
It will ask you a series of questions to help you configure it. I prefer defining the configuration on my own, so I’ll create the configuration file — .eslintrc.js
(ESLint supports JSON and YAML as well). with the following content:
Now we’ll make sure ESLint will work with the packages we’ve installed. We need to configure the parser, make sure the plugin is configured and the rule set applied is extended by the ones we’ve downloaded. Modify the file to look like so:
We’ve told ESLint to parse out Typescript code properly, and to use a recommended set of rules (under the ‘extends’ field, this part is optional) from an installed plugin.
Next we’ll add basic rules for React, courtesy of the Create React App development team. Add them to the file like so:
So we have linting for both Typescript and React, let’s add a code formatter. Prettier is my weapon of choice, as it does a great job at detecting and fixing style errors, and has superb ESLint integration.
To add Prettier support, we need to install a few dependencies:
npm i -D prettier eslint-config-prettier eslint-plugin-prettier
eslint-config-prettier will disable any linting rule that might interfere with an existing Prettier rule, and eslint-plugin-prettier will run Prettier analysis as part of ESLint.
Let’s add them to our ESLint config:
Go ahead, write poorly formatted code and you’ll see how Prettier is yelling at you. You are welcome to add your own custom Prettier configuration!
Basically we’re done. It should all work nice and easy, allowing us to keep our code linted and formatted like pros!
ESLint and Prettier are very powerful tools, and my article scratches the surface of their abilities, but it should get you started easily. I encourage you to explore more abilities and plugins that are available.
If you’d like a basic working project with my configuration, you’re welcome to take a look here.
A little bonus for those who stuck around and work with the all-mighty Visual Studio Code (my go-to IDE for web development) — ESLint and Prettier both have excellent integration with VSCode.
First, install the ESLint and Prettier VSCode extensions:
ext install esbenp.prettier-vscode dbaeumer.vscode-eslint
Both come with various configuration options to play with, but their defaults are pretty good. The only thing we need to change is ESLint’s default behavior to only inspect *.JS and *.JSX files. Add this configuration option to your settings:
the autoFix key speaks for itself I believe, ESLint will try to fix all the errors it can (some are impossible to fix automatically). You can of course disable it if you prefer fixing the errors yourself. Now you’ll see all of the errors right in your IDE, so no one can miss them. I recommend combining ESLint with Husky to make linting a must for every commit, but that’s up to you and your team.
Thank you for reading!
This article is a result of a quite frustrating personal experience trying to configure ESLint with no proper guide to help me through (except for the packages’ documentations). After struggling for several hours for something that felt like it should have taken five minutes, I decided to write this article so other developers won’t face the same struggle.
This is my first dev.to article, be gentle with me 😄 I welcome constructive criticism and general comments.
This article was published here as well.
Top comments (15)
Great article Dor! Quick question - how do you run eslint? From the command line? Have you found any way to tightly integrate with create-react-app? In other words,
npm start
should run your linter instead of create-react-app's.Thank you!
I've looked into that a while ago. There's an issue on the create-react-app GitHub about that (I'll link it when I find it), basically they say that the ESLint configuration react-scripts uses cannot be altered, and it contains only rules that might prevent bugs (such as unused variable).
I run it with the command line, and I've set up git hooks to run it on every commit (using husky and lint-staged).
Thanks for the response, Dor. Running husky/lint-staged is exactly what I am thinking of.
BTW, I am aware of the issue on the CRA repo: github.com/facebook/create-react-a.... See my comment on it related to this.
I was actually referring to this issue. Dan Abramov seemed pretty adamant there.
Ah, thanks for digging it up!
Great article, however in my case it didn't work. Running
./node_modules/.bin/eslint .
just didn't output anything. After a few hours of cursing the universe, I found a solution. ESLint works out-of-the-box only for .js, so I had to tell it to lint .ts as well. It can be done by adding--ext ts
../node_modules/.bin/eslint --ext ts .
Hope it helps somebody!
Thank you, great tutorial!,
finally my ESlint works for TS almost properly.
Though, for me there is some rule conflict between eslint and prettier
and it either always inserts once 2 spaces on next file save 4 spaces. Or some weird tab is inserted.
Anyone same problem? How to fix, please?
I tried literally every possible combination of settings for
vscode workspace:
codepile.net/pile/83MNXYDz
prettier:
codepile.net/pile/ZwNz6vwE
eslint:
codepile.net/pile/4Q7Y0BxM
I have macOS Sierra 10.12.6
VSCode v. 1.35.1.
screenshot:
ibb.co/9Y7xSVp
SOLVED:
youtube.com/watch?v=mg_pDqszL3g
add rule "@typescript-eslint/indent": "off" to .eslintrc
I'm sorry I didn't get a chance to look into your problem, but I'm glad you figured it out. I've faced the same issue and solved it this way too.
No problem, I'm glad it works! Thanks!
Great post. I'm using eslint, prettier and TypeScript for my blog. I'm also a big fan of husky.
Here's my repository if you're interested.
nickytonline / iamdeveloper.com
Source code for my web site iamdeveloper.com
iamdeveloper.com
Hey there, I'm Nick and this is my site's source code. This site started off as a clone of the Netlify CMS Gatsby Starter (check it out!). Since then, I've tweaked it a lot and converted the codebase to TypeScript.
Feel free to peruse the code and/or fork it.😉
Thanks to all the wonderful projects that made it possible to build this blog.
To get up and running:
git clone git@github.com:nickytonline/www.iamdeveloper.com.git
orgit clone https://github.com/nickytonline/www.iamdeveloper.com.git
npm install
npm run develop
to get up and running with the Gatsby development server.npm run type-check:watch
I wasn't aware of
'plugin:@typescript-eslint/recommended'
. I'm going to add that to my eslint config. Thanks and looking forward to your next post!Thank you very much! I'll be sure to check it.
I was going through the same thing creating multiple TypeScript + React apps with the same configuration as you've spelled out so I created and npx package to do just that: npmjs.com/package/create-react-typ....
It looks really cool! I'll be sure to check it out when I get the chance.
Hey, great article on the setup of eslint & prettier for a TypeScript project. I was planning on writing a article on this exact topic, but you've pretty much covered everything on the topic 👍🏼.