Open
Description
Before You File a Proposal Please Confirm You Have Done The Following...
- I have searched for related issues and found none that match my proposal.
- I have searched the current rule list and found no rules that match my proposal.
- I have read the FAQ and my problem is not listed.
My proposal is suitable for this project
- I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).
Link to the rule's documentation
https://typescript-eslint.io/rules/no-unused-vars/
Description
Currently all no-unused-vars
errors are not fixable. This is for good reasons, eg:
- side-effects are possible nearly everywhere in JS and it's impossible for us to know if an expression has a side-effect
- unused variables are a common part of the developer workflow and many people use autofix-on-save in their IDE -- so a fixer would cause "soon to be used" variables from being auto-deleted accidentally (an obviously frustrating DevX!)
With that being said there is one subset of unused variables which are generally safe to autofix -- imported names. These are generally safe to fix because:
- the vast, vast, vast majority of modules do not have top-level side-effects
- most bundlers and minifiers run on the assumption that modules DO NOT have side-effects!
- imports are mostly managed by the IDE (eg an IDE will auto-add import on usage of imported thing) and so removing a "soon to be used" import generally is low-impact from DevX.
There's evidence that the community wants this -- for example eslint-plugin-unused-imports
exists and is pretty widely used (they have ~8.4% of our weekly downloads). This plugin introduces two rules -- both are just monkey-patched extension rules on top of our no-unused-vars
implementation where one rule only reports on variables and the other only reports on imports and provides a fixer.
My proposal is the following:
- add a new option, say
enableAutofixRemoval: { imports: boolean }
with defaultenableAutofixRemoval: { imports: false }
(i.e. disable the autofixer by default). - build an autofixer for imported names that does the following:
- if the unused name is a namespace import, remove the entire import declaration.
- if the unused name is a default import:
- if there are no used named imports in the declaration, remove the entire import declaration.
- if there are used named imports in the declaration, just remove the unused default import.
- if the unused name is a named import:
- if there are no other used names in the declaration, remove the entire import declaration.
- if there are used names in the declaration, just remove the unused named import.
- if
enableAutofixRemoval.imports === true
- then set the fixer from (2) as an auto-fixer
- else set the fixer from (2) as a suggestion fixer
Additional Info
Namespace:
import * as Unused from 'foo';
import * as Used from 'foo';
export { Used };
autofixes to:
import * as Used from 'foo';
export { Used };
Default:
import Unused1 from 'foo';
import Unused2, { Used } from 'foo';
export { Used };
autofixes to:
import { Used } from 'foo';
export { Used };
Named:
import { Unused1 } from 'foo';
import Used1, { Unused2 } from 'foo';
import { Unused3, Used2 } from 'foo';
import Used3, { Unused4, Used4 } from 'foo';
export { Used1, Used2, Used3, Used4 };
autofixes to:
import Used1 from 'foo';
import { Used2 } from 'foo';
import Used3, { Used4 } from 'foo';
export { Used1, Used2, Used3, Used4 };