Standardizing TypeScript with NPM, ESLint, and Prettier
Tags: typescript, javascript, tutorial, beginners
Published: 2019-11-28 06:24:54

---
title: Standardizing TypeScript with NPM, ESLint, and Prettier
published: true
cover_image: https://i0.wp.com/killalldefects.com/wp-content/uploads/2019/11/image-54.png?ssl=1
date: 2019-11-28 06:12:09 UTC
series: Quality JavaScript with TypeScript
tags: TypeScript,JavaScript,Tutorial,Beginners
canonical_url: https://killalldefects.com/2019/11/28/standardizing-typescript-with-eslint-npm-prettier/
---

Once you get started with TypeScript in a new or old project, it’s important to set standards for code going forward. This is why I add linting and formatting support to TypeScript projects via ESLint and Prettier. In this article, I’ll show you how this is done and why it’s important.

## Wait, linting? Don’t I have TypeScript for that?

While the TypeScript compiler will enforce code correctness via its static type checking, it doesn’t do a few important things. Specifically, it checks your code to see if it compiles. A linter, in turn checks to see if code follows best practices in the JavaScript ecosystem.

Think about these two like a spell checker and a grammar checker. The following “sentence” would pass a spell checker:

`Frog cloud red molecule ambivalent forty two.`

A grammar checker would look at the above and think that I was losing my mind (and possibly be correct).

In much the same way, TypeScript compiler just checks that your code makes sense syntactically. A linter looks to augment that by telling you things like:

- Don’t use the `any` keyword
- Don’t declare marker (empty) interfaces
- Use camelCase naming notation
- Use a consistent string format
- Don’t use `ts-ignore`

Essentially, a linter keeps you honest by challenging some of the questionable things you might add to your code over time. This can be especially handy when bringing new developers onto a team or project.

Linters are by their very nature opinionated, but these opinions can be changed. By using configuration files (as we’ll see later on) and including rulesets of your choosing, you have control over exactly how picky your linter is.

## Introducing ESLint

ESLint is a very popular JavaScript and TypeScript linter that can parse JavaScript and TypeScript code and output warnings and errors based on the severity of the various rules violated.

Incidentally, ESLint will output an error code if it encounters any error-level severity rule violations. This can be used as part of your build pipeline to not accept new commits including rule violations, for example.

In the past, I’ve recommended using TSLint for TypeScript linting, but in early 2019 [Palantir announced they were deprecating TSLint in favor of ESLint](https://medium.com/palantir/tslint-in-2019-1a144c2317a9). Because of this, I advocate for migrating off of TSLint eventually in existing projects and using ESLint from the start for new projects.

Let’s install ESLint into an existing TypeScript application that does not use linting currently and see how that process works.

## Getting Started with NPM

I’m going to start with my code from my [Migrating to TypeScript article](https://killalldefects.com/2019/10/27/migrating-javascript-to-typescript/). This is a simple TypeScript application free from any single page application complexities. No Angular, React, Vue, or even JQuery to focus on – just the TypeScript and its generated JavaScript code.

This code is available on [GitHub](https://github.com/IntegerMan/MigratingToTypeScript) and we will be starting from the [migrateEnd tag](https://github.com/IntegerMan/MigratingToTypeScript/tree/migrateEnd) if you want to follow along.

For the purposes of this article, I’m going to be using Node Package Manager (NPM) to manage my dependencies and build steps. This article assumes you’ve already installed it on your machine. If that’s not the case, go ahead and [install the latest LTS version of NPM](https://www.npmjs.com/get-npm).

Since NPM isn’t configured in my sample repository, I’m going to run `npm init` from the command line to create a new `package.json` file. NPM init will ask you a series of questions, all of which have default options listed in parentheses which can be accepted by hitting enter. Regardless of your selections, a `package.json` file will be created.

Mine looks like this:

{% gist https://gist.github.com/IntegerMan/533cc6dedba1b51d5a20ee507aa9f6b9 %}

Bear in mind that a lot of this only matters if you want to publish your package online, which we will not be doing in this article.

Note the `scripts` section of this document. Each entry in this list can be run via `npm run [scriptname]`. NPM actually has all the tools needed to compose fairly complicated multi-step build processes.

Let’s add our own script definitions to this to support transpiling TypeScript to JavaScript:

```json
"scripts": {
    "transpile": "tsc",
    "build": "npm run transpile",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
```

Here we have a new `transpile` step that can be executed via `npm run transpile`. This will in turn execute `tsc` to transpile the TypeScript to JavaScript. Admittedly this is far more keystrokes to get the same effect, but the upside of this is that we can start to compose multi-part builds.

I also define the `build` step, which we’ll use to run multiple steps in a single command. In this case the `build` step simply runs the `transpile` step, but we’ll see this expand in the next section as we add in ESLint.

## Installing ESLint

Next, lets set up ESLint and linting process. We’ll use `npm` to install the development dependency on ESLint by running the following command:

`npm i -D typescript eslint eslint-config-typescript`

Here the `i` refers to the _install_ command and `-D` instructs NPM to save the dependency in `package.json` as a development-only dependency.

This will download the needed dependencies into your `node_modules` folder and write entries to your `package.json` based on the versions of dependencies pulled. For me, at the time of writing this article, these versions were pulled:

```json
"devDependencies": {
    "eslint": "^6.7.1",
    "eslint-config-typescript": "^3.0.0",
    "typescript": "^3.7.2"
  }
```

This essentially instructs any future `npm i` command to look for these dependencies or something more recent (indicated by the `^` character).

## Configuring ESLint for TypeScript

Now that ESlint is installed, let’s configure it. To do this, run `eslint --init`.

You should get a prompt asking you how you want ESLint to behave. For our purposes, we don’t want it to enforce code style, so select **check syntax and find problems**.

Next, ESLint will ask you what type of JavaScript module structures you use. In my case, I kept things simple by not using modules for my last article, so I’ll select **none of these**.

After that, ESLint asks if you use a single page application framework. My sample is just plain-old-JavaScript interacting with the DOM, so I’ll choose **none of these** again.

Next, ESLint asks if we use TypeScript. Boy, do we! That’s an easy **yes**.

Next ESLint asks what environment our code runs in. In this case, the code is meant to run in the browser, so the default choices are fine.

Finally, ESLint asks how we want to store our settings. You can pick whichever option you prefer, but for the purposes of this article I’ll be going with **JSON** because it’s the most natural to me when working with TypeScript files and `packages.json` already.

ESLint may ask you if you want to install additional dependencies based on which choices you chose. Say yes.

With that, your ESLint settings are configured and stored in an `.eslintrc.json` file that looks something like this:

{% gist https://gist.github.com/IntegerMan/e0e7eb7f499d54870267111672f145e6 %}

## Analyzing TypeScript with ESLint

Cool! So how do we use this?

Well, the syntax is somewhat complex and I don’t love to type it every time, but it looks something like `eslint --ext .ts [pathtosource]`.

Here we’re saying “run ESLint on only TypeScript files, and look in the specified directory and subdirectories”. Since my sample app has its typescript files in the root directory, I run `eslint --ext .ts .` to specify the current directory holds my source.

Running this on my sample code yields some violations:

![](https://i0.wp.com/killalldefects.com/wp-content/uploads/2019/11/image-54.png?w=770&ssl=1)

Well, that’s great! We wanted to find potentially questionable behavior, so we know linting is doing its job.

Lets save ourselves a bit of time for next time by updating our `package.json` scripts:

```json
"lint": "eslint --ext .ts .",
"build": "npm run lint && npm run transpile",
```

Here we define a new step just for linting and we expand our `build` step via the `&&` operator to have it call the lint step, wait for the result, and then call the transpile step only if the lint step executes without error.

Now we can just run `npm run build` to lint and transpile our TypeScript down to JavaScript.

## Fixing ESLint Issues

But what about our errors? We need to fix those, for certain.

In this case, my errors are false positives. That is, I’m relying on click handlers in my HTML to call to the functions defined in my JavaScript and my linter has no idea that this is what I’m doing.

When you think about it, though, the relationship between that JavaScript function and the HTML file isn’t going to be obvious to a new developer on the project working on something else and they could easily delete, rename, or move functions around not understanding the full impact of that choice.

To guard against that – and solve my ESLint warnings – I’m going to show you an example of fixing this.

In my HTML file, I remove the relevant `onclick="addTestCase()"` line and instead modify my code behind to grab the button by its ID and then set the `onclick` handler in code:

{% gist https://gist.github.com/IntegerMan/077766a118f99751b68074e54cbcd08d %}

_Note: if the indentation, quotes, and/or braces in the snippet above cause you brain trauma, I apologize, it’s to prove a point and will be resolved later._

This resolves _one_ of our errors. We could follow the same pattern to resolve the other issues, or I could use the opportunity to show you how to ignore false-positives.

* * *

Let’s say I disagree with the `no-unused-vars` rule. I shouldn’t since it’s a very good rule, but I might want to tweak its severity down to a warning or disable it entirely.

I do this by going into the `eslintrc.json` file and declaring my hatred for the rule by adding its identifier to the `rules` collection in the file as follows:

```json
"rules": {
    "no-unused-vars": "warn"
}
```

If I don’t want errors or warnings, I could set it instead to `off`. Please don’t do this. This is a good rule and should be an error or a warning, but this illustrates how to disable rules you disagree with.

Since I agree with the rule, I actually don’t want to disable it or make it a non-error, so I’m going to disable it on a line-by-line basis inside of my code instead. That makes a lot more sense with single cases of false positives.

I do this via the `disable-next-line` syntax:

```ts
// eslint-disable-next-line no-unused-vars
function deleteTestCase(id: number) {
  // my logic here
}
```

Whatever way you want to handle it, this gives us the tools that we need to get down to 0 errors in ESLint and a passing `npm run build` command.

## Coding with Style using Prettier

So, the linter catches code issues, but it clearly doesn’t care what kind of crazy indentation styling I choose. This is a problem in a production application where code standards are important.

Thankfully, a tool called Prettier helps with not only detecting, but also _automatically fixing_ styling issues. This standard set of formatting rules takes the debate out of code review and lets you focus on what really matters – the actual code.

Sure, the styles might not be exactly what you would have gone with on your own, but you soon learn to read the code style and even think in it.

## Installing and Configuring Prettier

While Prettier can operate as a stand-alone tool, it functions much more smoothly when integrated directly into ESLint. That way, Prettier will execute any time linting occurs.

We’ll start by installing the development dependencies for the Prettier ESLint plugin via the following command:

`npm i -D prettier eslint-plugin-prettier eslint-config-prettier`

Once that completes, we’ll need to modify our `eslintrc.json` file so that it knows about Prettier.

In the `extends` section, add the following two entries:

```json
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
```

Now, when I run my `lint` or `build` tasks via `npm`, I get a raft of failures around indentation, quotes, etc. This is now enforcing a style and rejecting files that do not meet it.

Well, that’s annoying and not extremely helpful in the real world. What would be more helpful would be if Prettier could automatically format my files properly. Thankfully, it can.

All we have to do is modify our `lint` script in `package.json` to add `--fix` to the command line arguments like so:

`"lint": "eslint --fix --ext .ts ."`

Once we re-run that, our source files are automatically modified to be correctly formatted.

This is possible because some ESLint rules have automatic fixes defined which ESLint can apply automatically if you specify the `--fix` flag.

This isn’t just limited to formatting, either – some trivial JavaScript and TypeScript rules provide automatic fixes, meaning the very act of checking your code for serious issues can fix minor issues automatically, while enforcing a consistent style throughout your codebase.

## Recommendations

Give NPM, ESLint, and Prettier a shot to see how you like working with them.

If you’re curious about ESLint’s rules or configuration, take a look at the [TypeScript recommended ruleset](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin) for details on the individual rules, their default settings, and how you can customize their behavior.

My finding is that TypeScript mixed with NPM, ESLint, and Prettier offers the right amount of standards enforcement and consistency to help teams scale in JavaScript development, which is really the point of wanting to use TypeScript to begin with.

The post [Standardizing TypeScript with NPM, ESLint, and Prettier](https://killalldefects.com/2019/11/28/standardizing-typescript-with-eslint-npm-prettier/) appeared first on [Kill All Defects](https://killalldefects.com).