Skip to content

Commit 57bfbb5

Browse files
committed
Allow underscore prefix to bypass noUnusedLocals warning
This PR continues [Allow leading underscore for types...](#58884), taking into account feedback from https://github.com/microsoft/TypeScript/pull/58884/files#r1643108204. The initial commit on this PR is original work by @a-tarasyuk. The second commit enhances the test suite and reverts the change to checker.ts to get a new baseline on the test suite for easier comparison with the changes. The third commit changes checker.ts to allow any unused local if it is prefixed with an underscore. This has the effect of newly allowing the following unused declarations: ```ts // Variables were previously allowed only in destructuring and for-loops const _unusedVar = 2; let _unusedLet = 4; var _unusedVar2 = 6; function _unusedFunc() { } const _unusedArrow = () => { }; class _UnusedClass { } interface _UnusedInterface { } type _UnusedType = string; enum _UnusedEnum { A } namespace _UnusedNamespace { ... } ``` As far as I can tell, enum members and properties are not checked in the checkUnusedLocalsAndParameters function, and we do not need to special-case them. Closes #58561
1 parent 8b41116 commit 57bfbb5

File tree

3 files changed

+4
-60
lines changed

3 files changed

+4
-60
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44409,21 +44409,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4440944409
return tryCast(getRootDeclaration(node), isParameter);
4441044410
}
4441144411

44412-
function isValidUnusedLocalDeclaration(declaration: Declaration): boolean {
44413-
if (isBindingElement(declaration)) {
44414-
if (isObjectBindingPattern(declaration.parent)) {
44415-
/**
44416-
* ignore starts with underscore names _
44417-
* const { a: _a } = { a: 1 }
44418-
*/
44419-
return !!(declaration.propertyName && isIdentifierThatStartsWithUnderscore(declaration.name));
44420-
}
44421-
return isIdentifierThatStartsWithUnderscore(declaration.name);
44422-
}
44423-
return isAmbientModule(declaration) ||
44424-
(isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!);
44425-
}
44426-
4442744412
function checkUnusedLocalsAndParameters(nodeWithLocals: HasLocals, addDiagnostic: AddUnusedDiagnostic): void {
4442844413
// Ideally we could use the ImportClause directly as a key, but must wait until we have full ES6 maps. So must store key along with value.
4442944414
const unusedImports = new Map<string, [ImportClause, ImportedDeclaration[]]>();
@@ -44438,7 +44423,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4443844423

4443944424
if (local.declarations) {
4444044425
for (const declaration of local.declarations) {
44441-
if (isValidUnusedLocalDeclaration(declaration)) {
44426+
const name = getNameOfDeclaration(declaration);
44427+
if (name && isIdentifierThatStartsWithUnderscore(name)) {
4444244428
continue;
4444344429
}
4444444430

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
noUnusedLocals_types.ts(4,6): error TS6196: 'UnusedType1' is declared but never used.
22
noUnusedLocals_types.ts(5,11): error TS6196: 'UnusedInterface1' is declared but never used.
33
noUnusedLocals_types.ts(6,7): error TS6196: 'UnusedClass1' is declared but never used.
4-
noUnusedLocals_types.ts(9,6): error TS6196: '_UnusedType2' is declared but never used.
5-
noUnusedLocals_types.ts(10,11): error TS6196: '_UnusedInterface2' is declared but never used.
6-
noUnusedLocals_types.ts(11,7): error TS6196: '_UnusedClass2' is declared but never used.
7-
noUnusedLocals_types.ts(15,6): error TS6196: '_Helper' is declared but never used.
84

95

10-
==== noUnusedLocals_types.ts (7 errors) ====
6+
==== noUnusedLocals_types.ts (3 errors) ====
117
// Test specifically for type declarations with underscore prefix
128

139
// These should all produce errors (no underscore)
@@ -23,19 +19,11 @@ noUnusedLocals_types.ts(15,6): error TS6196: '_Helper' is declared but never use
2319

2420
// These should NOT produce errors (underscore prefix)
2521
type _UnusedType2 = string;
26-
~~~~~~~~~~~~
27-
!!! error TS6196: '_UnusedType2' is declared but never used.
2822
interface _UnusedInterface2 { x: number; }
29-
~~~~~~~~~~~~~~~~~
30-
!!! error TS6196: '_UnusedInterface2' is declared but never used.
3123
class _UnusedClass2 { }
32-
~~~~~~~~~~~~~
33-
!!! error TS6196: '_UnusedClass2' is declared but never used.
3424

3525
// Mixed usage - only the one without underscore should error
3626
type UsedInOther = number;
3727
type _Helper = UsedInOther; // _Helper is not an error, but it uses UsedInOther
38-
~~~~~~~
39-
!!! error TS6196: '_Helper' is declared but never used.
4028

4129
export {};

tests/baselines/reference/unusedLocalsStartingWithUnderscore.errors.txt

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
11
a.ts(2,7): error TS6133: 'unusedVar' is declared but its value is never read.
2-
a.ts(3,7): error TS6133: '_unusedVar' is declared but its value is never read.
32
a.ts(5,5): error TS6133: 'unusedLet' is declared but its value is never read.
4-
a.ts(6,5): error TS6133: '_unusedLet' is declared but its value is never read.
53
a.ts(8,5): error TS6133: 'unusedVar2' is declared but its value is never read.
6-
a.ts(9,5): error TS6133: '_unusedVar2' is declared but its value is never read.
74
a.ts(12,10): error TS6133: 'unusedFunc' is declared but its value is never read.
8-
a.ts(13,10): error TS6133: '_unusedFunc' is declared but its value is never read.
95
a.ts(15,7): error TS6133: 'unusedArrow' is declared but its value is never read.
10-
a.ts(16,7): error TS6133: '_unusedArrow' is declared but its value is never read.
116
a.ts(19,7): error TS6196: 'UnusedClass' is declared but never used.
12-
a.ts(20,7): error TS6196: '_UnusedClass' is declared but never used.
137
a.ts(23,11): error TS6196: 'UnusedInterface' is declared but never used.
14-
a.ts(24,11): error TS6196: '_UnusedInterface' is declared but never used.
158
a.ts(27,6): error TS6196: 'UnusedType' is declared but never used.
16-
a.ts(28,6): error TS6196: '_UnusedType' is declared but never used.
179
a.ts(31,6): error TS6196: 'UnusedEnum' is declared but never used.
18-
a.ts(32,6): error TS6196: '_UnusedEnum' is declared but never used.
1910
a.ts(36,12): error TS6133: 'x' is declared but its value is never read.
2011
a.ts(38,12): error TS6133: 'x' is declared but its value is never read.
2112
a.ts(41,11): error TS6133: 'UnusedNamespace' is declared but its value is never read.
22-
a.ts(44,11): error TS6133: '_UnusedNamespace' is declared but its value is never read.
2313
a.ts(49,7): error TS6133: 'unusedA' is declared but its value is never read.
2414
a.ts(51,8): error TS6133: 'unusedC' is declared but its value is never read.
2515
a.ts(63,7): error TS6196: 'TestClass' is declared but never used.
@@ -36,75 +26,57 @@ a.ts(81,7): error TS6133: 'obj' is declared but its value is never read.
3626
declare function get(): string;
3727
export { get };
3828

39-
==== a.ts (32 errors) ====
29+
==== a.ts (22 errors) ====
4030
// Variables
4131
const unusedVar = 1; // error
4232
~~~~~~~~~
4333
!!! error TS6133: 'unusedVar' is declared but its value is never read.
4434
const _unusedVar = 2; // ok
45-
~~~~~~~~~~
46-
!!! error TS6133: '_unusedVar' is declared but its value is never read.
4735

4836
let unusedLet = 3; // error
4937
~~~~~~~~~
5038
!!! error TS6133: 'unusedLet' is declared but its value is never read.
5139
let _unusedLet = 4; // ok
52-
~~~~~~~~~~
53-
!!! error TS6133: '_unusedLet' is declared but its value is never read.
5440

5541
var unusedVar2 = 5; // error
5642
~~~~~~~~~~
5743
!!! error TS6133: 'unusedVar2' is declared but its value is never read.
5844
var _unusedVar2 = 6; // ok
59-
~~~~~~~~~~~
60-
!!! error TS6133: '_unusedVar2' is declared but its value is never read.
6145

6246
// Functions
6347
function unusedFunc() { } // error
6448
~~~~~~~~~~
6549
!!! error TS6133: 'unusedFunc' is declared but its value is never read.
6650
function _unusedFunc() { } // ok
67-
~~~~~~~~~~~
68-
!!! error TS6133: '_unusedFunc' is declared but its value is never read.
6951

7052
const unusedArrow = () => { }; // error
7153
~~~~~~~~~~~
7254
!!! error TS6133: 'unusedArrow' is declared but its value is never read.
7355
const _unusedArrow = () => { }; // ok
74-
~~~~~~~~~~~~
75-
!!! error TS6133: '_unusedArrow' is declared but its value is never read.
7656

7757
// Classes
7858
class UnusedClass { } // error
7959
~~~~~~~~~~~
8060
!!! error TS6196: 'UnusedClass' is declared but never used.
8161
class _UnusedClass { } // ok
82-
~~~~~~~~~~~~
83-
!!! error TS6196: '_UnusedClass' is declared but never used.
8462

8563
// Interfaces
8664
interface UnusedInterface { } // error
8765
~~~~~~~~~~~~~~~
8866
!!! error TS6196: 'UnusedInterface' is declared but never used.
8967
interface _UnusedInterface { } // ok
90-
~~~~~~~~~~~~~~~~
91-
!!! error TS6196: '_UnusedInterface' is declared but never used.
9268

9369
// Type aliases
9470
type UnusedType = string; // error
9571
~~~~~~~~~~
9672
!!! error TS6196: 'UnusedType' is declared but never used.
9773
type _UnusedType = string; // ok
98-
~~~~~~~~~~~
99-
!!! error TS6196: '_UnusedType' is declared but never used.
10074

10175
// Enums
10276
enum UnusedEnum { A } // error
10377
~~~~~~~~~~
10478
!!! error TS6196: 'UnusedEnum' is declared but never used.
10579
enum _UnusedEnum { A } // ok
106-
~~~~~~~~~~~
107-
!!! error TS6196: '_UnusedEnum' is declared but never used.
10880

10981
// Declarations in for loops
11082
for (const _x of []) { } // ok
@@ -123,8 +95,6 @@ a.ts(81,7): error TS6133: 'obj' is declared but its value is never read.
12395
export const x = 1;
12496
}
12597
namespace _UnusedNamespace { // ok
126-
~~~~~~~~~~~~~~~~
127-
!!! error TS6133: '_UnusedNamespace' is declared but its value is never read.
12898
export const x = 1;
12999
}
130100

0 commit comments

Comments
 (0)