149

I use ESLint in all of my TypeScript projects with the following settings:

  "extends": ["airbnb", "prettier", 'plugin:vue/recommended'],
  "plugins": ["prettier"],
  "parserOptions": {
  "parser": "@typescript-eslint/parser",
  "ecmaVersion": 2018,
  "sourceType": "module"
  },
  • a bunch of custom rules. I've also installed the following dependencies for TypeScript support:

      "@typescript-eslint/eslint-plugin": "^1.7.0",
      "@typescript-eslint/parser": "^1.7.0",
    

However, one of ESLint's most useful rules, https://eslint.org/docs/rules/no-unused-vars, seems to be very poorly configured for TypeScript projects. For example, when I export an enum, the rule warns me that the enum isn't in use in the file where it is declared:

export enum Foo {
   Bar,
}

Similarly, when I import an interface or class to be used as a type, 'no-unused-vars' will complain again on the the line of the actual import:

In Foo.ts

export interface Foo {
   bar: string;
}

In bar.ts

import { Foo } from './Foo'
const bar: Foo = { bar: 'Hello' };

Is there any way to configure the no-unused-vars rule to take these two cases into account? I'm not a fan of disabling the rule, as it is one of the most helpful rules in my entire ruleset outside of these cases.

I've already downgraded the rule to only give a warning instead of an error, but having all my documents filled with warnings still kind of defeats the purpose of using esLint.

Filling my all my documents with //eslint-disable-line as suggested here also seems like a bad solution.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
Rins
  • 1,771
  • 2
  • 13
  • 13
  • It seems that es lint is not properly configured. Try uninstalling and again adding eslint in your package. – Rohan Agarwal Sep 05 '19 at 09:13
  • I would be surprised if that was the case as I get the same problem even after re-installing esLint (and when starting completely new projects). I thought everyone had the same experience, but perhaps it is caused by one of the rule-sets I extend my esLint settings from? – Rins Sep 05 '19 at 10:05

11 Answers11

197

I think the use of "plugin:@typescript-eslint/eslint-recommended" introduces bunch of unwanted rules. One is probably better off using "@typescript-eslint/no-unused-vars" ESLint rule instead.

{
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint",
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
  ],
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": ["error"]
  }
}

Note: be sure to restart your server after making the above change.

Reference - https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md

Jerad Rose
  • 15,235
  • 18
  • 82
  • 153
jaibatrik
  • 6,770
  • 9
  • 33
  • 62
  • 8
    This should be the current accepted solution. adding rules for `no-unused-vars` and `@typescript-eslint/no-unused-vars` is what worked for me. The accepted solution didn't detect unused var errors. – kimbaudi Jul 28 '21 at 16:11
  • The other solutions did not work for me. This is the only one that worked. This should be the current accepted solution. – b.lyte May 26 '22 at 23:57
  • 2
    This is just disabling the rule. It has nothing to do with it being an interface. so this just turns this, useful rule off. Which is not what you want to do – Liam Jul 19 '22 at 19:24
  • 3
    To quote the OP in the question *I'm not a fan of disabling the rule* – Liam Jul 19 '22 at 19:24
  • @Liam It's disabling the original rule and adding a compatible rule back. This is what the `typescript-eslint` project recommended. – jaibatrik Jul 25 '22 at 10:11
  • This isn't how you do that – Liam Jul 25 '22 at 11:41
  • @Liam This is definitely correct. If you disable the original eslint rule and add the ts rule back, it will catch both JS and TS import errors. Try before saying it's wrong. – Arafat Zahan Aug 02 '22 at 19:38
  • 3 years later and this still works! – Drew Daniels May 11 '23 at 20:29
164

It's a bit buried in the documentation, but if you add some things to the 'extends' property, you can use both the rules recommended by ESLint like no-unused-vars, and have it actually work in Typescript. Like so:

"extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/eslint-recommended",
        "plugin:@typescript-eslint/recommended"
    ],

@typescript-eslint/recommended seems to be the thing that allows eslint:recommended to deal with Typescript constructs effectively. Not sure how it would affect your other extensions though.

dolios
  • 1,936
  • 1
  • 10
  • 10
  • 2
    Yeah, this does seem to fix the issue. As you said, it does conflict with some of my other extensions, but I should be able to figure that out once I get some time to experiment. Thank you very much! – Rins Oct 23 '19 at 13:04
  • 7
    The order was important for me. Ensure the `"plugin:@typescript-eslint/recommended"` is after other extensions – Nick Hammond Feb 03 '21 at 16:49
  • 1
    VS Code, using eslint, was giving me warnings about unused variables in my type declarations for function callbacks. These options, added to my .eslintrc.js fixed it all up for me. – memsetzero Apr 17 '21 at 21:26
  • 4
    i feel this answer is outdated. I already have `"plugin:@typescript-eslint/recommended"` in `extends` section of `eslintrc.json` so I added `"eslint:recommended"` and `"plugin:@typescript-eslint/eslint-recommended"` in the correct order, but eslint still could not detect unused var errors that vscode was detecting. Using solution by @jaibatrik or updated solution by @ghiscoding was what worked. – kimbaudi Jul 28 '21 at 16:09
  • @kimbaudi +1 It also won't let me do the typescript ignore comment line. I'm beginning to think typescript is more trouble than it's worth saving (at least for react) – Fiddle Freak Nov 06 '21 at 23:07
66

I got lot of false errors with latest TypeScript/ES-Lint versions and I found that they came up with an experimental rule to fix the no-unused-vars which is broken and with the experimental rule @typescript-eslint/no-unused-vars-experimental it finally works as I expect it to.

Prior to the change on my side, I had multiple false errors when using interfaces/types saying that these vars were unused (which of course they'll never be used since they're not variables but rather interfaces/types)... and in case you're curious about the code itself, here is the PR adding this experimental rule which is how I found the rule.

Here's a subset of my updated .eslintrc file

{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "@typescript-eslint/no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars-experimental": "error",
    "no-unused-vars": "off"
  }
}

and I'm now finally back to normal :)

EDIT (Jan. 2021)

As mentioned by Brad (a maintainer of the project) in the comment below, this is (was) a temporary solution and is now deprecated. From his comment (below), we can now use directly @typescript-eslint/no-unused-vars for the same intended behavior. Thanks to Brad for the info. I can also confirm that switching back to @typescript-eslint/no-unused-vars now works for me (I updated my code and it's all good now).

This is not the way to go, and you should avoid it. @typescript-eslint/no-unused-vars-experimental is deprecated, and will be removed in the next major. Update to the latest version of the tooling and just use @typescript-eslint/no-unused-vars. Source: I am the maintainer of the project.

UPDATED ANSWER since Jan. 2021

So here's the latest update of my .eslintrc file which works for me :)

{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "@typescript-eslint/no-unused-vars": "error",
    "no-unused-vars": "off"
  }
}
ghiscoding
  • 12,308
  • 6
  • 69
  • 112
  • 5
    This was the only solution that worked for me. I'm using xo with Typescript and kept getting all the no-unused-vars errors. – tjklemz Sep 16 '20 at 21:25
  • This worked for me, but this is a terrible solution from the eslint/typescript-eslint guys. Like this is an awful error to get when you're trying to declare function types – Brett East Jan 14 '21 at 04:51
  • I'm on Node and this has been the only solution that worked for typescript linting false unused-vars on enums and constructor defined attributes – Laszlo Sarvold Jan 14 '21 at 12:11
  • 4
    This is not the way to go, and you should avoid it. `@typescript-eslint/no-unused-vars-experimental` is deprecated, and will be removed in the next major. Update to the latest version of the tooling and just use `@typescript-eslint/no-unused-vars`. Source: I am the maintainer of the project. – Brad Zacher Jan 15 '21 at 23:05
  • Thanks Brad, I updated the answer in consequence of the upcoming change.. thanks again for this valuable new info. – ghiscoding Jan 16 '21 at 02:12
  • 4
    @BradZacher unfortunately, I am still running in to the same issue where an imported interface, being used as a return type, triggers this rule. I am using the following versions: "@typescript-eslint/eslint-plugin": "4.14.1", "@typescript-eslint/parser": "4.14.1", "eslint": "7.18.0", – jkossis Jan 26 '21 at 19:09
20

My issue was with using decorators and wanting to have a variable with an appropriate name for clarity, for example:

@OneToMany((type) => Employee) instead of @OneToMany(() => Employee)

The usual solution for TypeScript is to prefix with an underscore:

@OneToMany((_type) => Employee)

And it's possible to make ESLint accept the same:

.eslintrc.js

module.exports = {
  ...
  rules: {
    '@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_' }]
    ....
  },
};
thisismydesign
  • 21,553
  • 9
  • 123
  • 126
  • 5
    the rule to catch the full variety of declarations is: `"@typescript-eslint/no-unused-vars": ["error", {argsIgnorePattern: "^_", destructuredArrayIgnorePattern: "^_", varsIgnorePattern: "^_"}]` (src: https://eslint.org/docs/latest/rules/no-unused-vars#options) – fredrivett Sep 10 '22 at 21:54
8

For anyone looking to get no-unused-vars working properly in TypeScript when using YAML configuration, e.g. .eslintrc.yaml, it looks like this:

rules:

  "@typescript-eslint/no-unused-vars":
  - warn
  - argsIgnorePattern: "^_"                # <-- NOTE!
    varsIgnorePattern: "^_"
    caughtErrorsIgnorePattern: "^_"

  no-unused-vars: # disabled but see typescript-eslint/no-unused-vars
  - off
  ...
Andrew E
  • 7,697
  • 3
  • 42
  • 38
5

You have parser nested inside of parserOptions. It should be a sibling, like this:

"parser": "@typescript-eslint/parser",
"parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module"
},

As for no-unused-vars, I'm afraid this is an ongoing bug with @typescript-eslint: https://github.com/typescript-eslint/typescript-eslint/issues/363

Jay Kariesch
  • 1,392
  • 7
  • 13
  • 1
    Ahh, my mistake. I actually use the plugin:vue parser somewhere further down in the rule set, but I didn't think to specify that. According to https://eslint.vuejs.org/user-guide/#usage, specifying @typescript-eslint/parser under parserOptions.parser is valid. I'm very happy to hear that it is a known bug. I wasn't able to find much about it, and since it seems like such a common use case, I just assumed that I had done something wrong. Thank you very much! – Rins Sep 28 '19 at 06:03
5

Upgrading @typescript-eslint/eslint-plugin and @typescript-eslint/parser from 3.x to the latest 4.x resolved the issue for me.

supNate
  • 432
  • 3
  • 10
3

Also for me works rule /eslint no-unused-vars: ["error", { "varsIgnorePattern": "[iI]gnored" }]/
You can add it like this in your .eslintrc.json file (this one is for ignoring all Strings which start with Capital letter)

    "rules": {
        "no-unused-vars": [
          "error",
          {
            "varsIgnorePattern": "^[A-Z]"
          }
        ],
    }

For more information, and properties you can check this link.

chavy
  • 841
  • 10
  • 20
1

In my opinion, turning the rule off is a bit dangerous for projects where typescript and javascript are used simultaneously.

The solution is to define "overrides" on root level in .eslintrc.json file:

  "overrides": [
    {
      "files": ["*.ts"],
      "rules": {
        "no-unused-vars": "off"
      }
    }
  ],
Viktor M
  • 387
  • 3
  • 7
0

After couple of year still getting the same error. It's frustrate to try and check why it's not working. After trying lot of possible configuration here is the finally working for me. Incase someone had difficulties like me !

eslintrc.js

module.exports = {
    env: {
        browser: true,
        node: true,
    },
    parser: "@typescript-eslint/parser",
    extends: [
        "eslint:recommended",
        "plugin:@typescript-eslint/eslint-recommended",
        "prettier",
        "plugin:prettier/recommended",
        "plugin:@typescript-eslint/recommended",
    ],
    parserOptions: {
        ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
        project: "tsconfig.eslint.json",
        tsconfigRootDir: __dirname,
        sourceType: "module", // Allows for the use of imports
    },
    plugins: ["@typescript-eslint", "@typescript-eslint/tslint", "import", "unused-imports"],

    rules: {
        "@typescript-eslint/no-unused-vars": "off",
        "@typescript-eslint/no-unused-vars-experimental": "error",
        "no-unused-vars": "off",
        "import/order": "error",
        "no-console": ["warn", { allow: ["warn", "error"] }],
        eqeqeq: ["error", "always"],
        "no-else-return": "error",
    },
    settings: {
        "import/resolver": {
            node: {
                extensions: [".js", ".jsx", ".ts", ".tsx"],
                moduleDirectory: ["node_modules", "src/"],
            },
        },
    },
};
Dipak Telangre
  • 1,792
  • 4
  • 19
  • 46
0

I use this configuration and it works normally

{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true,
    "jest": true
  },
  "extends": ["airbnb-base", "prettier"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint", "jest"],
  "rules": {
    "import/extensions": "off",
    "@typescript-eslint/no-unused-vars": ["error"]
  },
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  }
}