简体   繁体   中英

eslint import/order breaks down when using typescript aliases

I am using typescript path aliases in a large react project. So for example, in my tsconfig.json, I specify some path aliases:

{
  "baseUrl": "./src",
    "paths": {
      "@common/*": ["common/*"],
      "@settings/*": ["settings/*"],
      // other paths
    }
}

Ok great, now when I want to import some modules I can uses these aliases. We are also using eslint, and one of the rules we use is the import/order . It enforces that anything coming out of node_modules should be imported before any local modules. I like this rule. Without using my aliases:

import React, { useEffect } from "react";
import SomeDistantComponent from '../../common/components/SomeDistantComponent'
import { Formik } from 'formik'

This will throw a linting error, but formatting the file according to eslint will automatically move the formik import above the SomeComponent import, which is what I want.

However, when using my aliases, this does not throw an error:

import React, { useEffect } from "react";
import SomeComponent from '@common/components/SomeComponent'
import { Formik } from 'formik'

Its as if the typescript path aliases have tricked the import/order rule, and that rule now breaks down.

Question: How can my linter still recognize these aliases paths? Can I configure the groups or pathGroups options of this plugin to properly group and order my aliased local modules to come after my node modules?

Bonus question:

I don't necessarily need to distinguish between aliased modules and non-aliased modules in terms of order. For example

import React, { useEffect } from "react";
import SomeCloseComponent from './SomeCloseComponent'
import SomeComponent from '@common/components/SomeComponent'
import AnotherCloseComponent from './AnotherCloseComponent'
import { Formik } from 'formik'

I'd be fine leaving the import order of SomeCloseComponent , SomeComponent , and AnotherCloseComponent , so long as the formik import goes before all of them. Is it possible to put aliased imports at the same 'priority' level of grouping as non-aliased imports, meaning they won't be reordered among themselves, but will all come after node_module imports?

Edit - making another attempt:

Based on Aviv Hadar's answer, I've tried this in my eslint file:

"import/order": [
      "warn",
      {
        pathGroups: [
          {
            pattern: "@material-ui/**",
            group: "external",
            position: "after"
          },
          {
            pattern: "@/**",
            group: "internal",
            position: "after"
          }
        ],
        pathGroupsExcludedImportTypes: ["internal", "external", "builtins"],
        groups: [
          "builtin",
          "external",
          "unknown",
          ["internal", "sibling", "parent"],
          "index",
          "object",
          "type"
        ]
      }
    ],

This works in that it treats all imports that begin with @ as internal, and keeps them on the same level as other internal imports. So this won't cause a warning:

import { Something } from "@some/aliased/path";
import LocalComponent from "../../local";
import { SomethingElse } from "@another/aliased/path";

Which is what I want - all internal modules at the same level of grouping, regardless of aliased vs not, or parent/sibling. However, this should show a warning, but it doesn't:

import { Something } from "@some/aliased/path";
import LocalComponent from "../../local";
import { SomethingElse } from "@another/aliased/path";
import { makestyles } from '@material-ui/styles'

The last import does begin with @ , but it is a node_module, and should be at the top of the list. In retrospect I wish we would have chosen a different alias prefix, but we didn't. Is there a way to tweak my config to properly interperet node_modules as external , and keep them in that group for ordering?

You need to use the pathGroups property to indicate to eslint that the correct position of paths that starts with @/ is before/after one of the other groups.

I choose to use the ~ symbol instead of @ to create a difference between importing from my src folder and importing from an external library that starts with @ , like this one for example:

import {makeStyles} from '@material-ui/core/styles';
import Bar from '~/components/Bar'

So now my file looks like this:

import React from 'react'; // external
import Bar from '~/components/Bar'; // SPECIAL
import {ReactComponent as Logo} from '../logo.svg'; // parent
import './App.css'; // sibling

And this is my definition of the import/order rule in my .eslintrc file:

    "import/order": [
      "error",
      {
        "pathGroups": [
          {
            "pattern": "~/**",
            "group": "external",
            "position": "after"
          }
        ],
        "groups": [
          "builtin",
          "external",
          "internal",
          "unknown",
          "parent",
          "sibling",
          "index",
          "object",
          "type"
        ]
      }
    ]
  }

As you can see, I'm using the pathGroups to tell eslint that the proper position of any import that starts with ~/ is after the external group.

Because each import here belongs to a different group, any change that I will do to this order will result in an ESLint error.

PS I had issues at some point with the imports themselves that were resolved after I updated the eslint-plugin-import to version 2.23.4

I have aliases like ~const/ and ~helpers/ . I was able to get it to work using this pattern:

{
    "pattern": "~*/**",
    "group": "external",
    "position": "after"
}

It is a wild card for anything that starts with ~ , and any directory or file within in.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM