In this post, I would like to show how you can use ESLint together with eslint-plugin-import to organize your TypeScript imports. Without these rules or manual reordering, your imports will start looking like this sooner or later:

import { Injectable } from "@angular/core";
import { Store } from "@ngrx/store";
import { LogRequest } from "@custom-lib";
import * as fromReducers from "../store/reducers";
import * as fromSelectors from "../store/selectors";
import { LoggingGroup, LoggingRequest } from "../models";
import { LoggingApiService } from "@custom-lib";
import { BehaviorSubject, Observable } from "rxjs";
import * as fromActions from "../store/actions";

So how do we go from that, to this?

import { Injectable } from "@angular/core";
import { Store } from "@ngrx/store";
import { BehaviorSubject, Observable } from "rxjs";

import { LoggingApiService, LogRequest } from "@custom-lib";

import { LoggingGroup, LoggingRequest } from "../models";
import * as fromActions from "../store/actions";
import * as fromReducers from "../store/reducers";
import * as fromSelectors from "../store/selectors";

In the example before, the order is mostly defined by the order in which imports were added. In the example after, we can see the imports being grouped nicely into categories: external imports, imports from @custom-lib, and those relative to the current file.

You can do everything by hand and while I like to have some sort of guide to adhere to, I find it a waste of time to do this. The same goes for pointing out styling errors in reviewing pull requests. And I’m sure you can think of better ways to spend your time too, right? This is where ESLint comes in. You define a set of rules, which automatically enforce code style. This means that you don’t have to point out errors in coding style anymore. ESLint will do so automatically.

Getting imports in order

To apply the ordering and sorting rules we first need to install eslint-plugin-import and add it as ESLint plugin:

npm i -D eslint-plugin-import

Add import to the plugins section of .eslintrc.json:

{
  "overrides": [
    {
      "plugins": ["import"]
    }
  ]
}

Add sort-imports and import/order to the rules section:

{
  "rules": [
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "parent", "sibling", "index"],
        "pathGroups": [
          {
            "pattern": "@custom-lib/**",
            "group": "external",
            "position": "after"
          }
        ],
        "pathGroupsExcludedImportTypes": ["builtin"],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ],
    "sort-imports": [
      "error",
      {
        "allowSeparatedGroups": true,
        "ignoreDeclarationSort": true,
      }
    ]
  ]
}

Here two rules are added: import/order and sort-imports. You might wonder what these do and it’s actually quite simple: the former is used for ordering and grouping imports and the latter is used for ordering import members (functions, objects and primitives). To make the configuration work, you should set allowSeparatedGroups and ignoreDeclarationSort are both set to true.

If you have questions about the rules and the options I picked, I recommend checking out the documentation. The rules are very well documented and contain code examples to illustrate what they do.

  • sort-imports - Sort imported members (docs)
  • import/order - Order and group imports (docs)

Icing on the cake

The configuration above will take care of sorting and grouping imports and import embers. While I was looking up the documentation, I found there were a few more rules that I think are beneficial for organizing imports.

{
  "rules": [
    "no-duplicate-imports": "error",
    "no-multiple-empty-lines": [
      "error",
      {
        "max": 1,
        "maxEOF": 0,
        "maxBOF": 0
      }
    ],
    "import/first": "error",
    "import/newline-after-import": "error",
    "import/no-duplicates": "error",
    "import/no-unassigned-import": "error"
  ]
}

Please note that everything I show here is configured as I saw fit. Do check out the documentation, find out what works for you and create a style guide that works for you or your team.

  • no-duplicate-imports - Disallow duplicate module imports (docs)
  • no-multiple-empty-lines - Disallow multiple empty lines (docs)
  • import/first - Ensure all imports appear before other statements (docs)
  • import/newline-after-import - Enforce a newline after import statements (docs)
  • import/no-duplicates - Report repeated import of the same module in multiple places (docs)
  • import/no-unassigned-import - Forbid unassigned imports (docs)

I hope this guide was useful. And as a bonus, most rules can be fixed automatically using --fix. What’s even better is that editors can be configured to apply linting fixes automatically. Now your editor is working for you!

Enjoy your well-organized import statements!