Skip to content

Commit 0474837

Browse files
committed
Fix: type-annotations are marked as used (fixes bradzacher#61)
1 parent 3edbe7d commit 0474837

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

lib/rules/no-unused-vars.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,80 @@ module.exports = {
125125
});
126126
}
127127

128+
/**
129+
* Checks if the given node has a type annotation and marks it as used.
130+
* @param {ASTNode} node the relevant AST node.
131+
* @returns {void}
132+
* @private
133+
*/
134+
function markTypeAnnotationAsUsed(node) {
135+
const annotation = node.typeAnnotation || node;
136+
137+
switch (annotation.type) {
138+
case "TSTypeReference": {
139+
if (annotation.typeName.type === "TSArrayType") {
140+
markTypeAnnotationAsUsed(
141+
annotation.typeName.elementType
142+
);
143+
} else {
144+
markVariableAsUsed(context, annotation.typeName.name);
145+
if (
146+
annotation.typeParameters &&
147+
annotation.typeParameters.params
148+
) {
149+
annotation.typeParameters.params.forEach(param => {
150+
markTypeAnnotationAsUsed(param);
151+
});
152+
}
153+
}
154+
155+
break;
156+
}
157+
case "TSUnionType":
158+
case "TSIntersectionType":
159+
annotation.types.forEach(type => {
160+
markTypeAnnotationAsUsed(type);
161+
});
162+
163+
break;
164+
165+
default:
166+
break;
167+
}
168+
}
169+
170+
/**
171+
* Checks if the given node has a return type and marks it as used.
172+
* @param {ASTNode} node the relevant AST node.
173+
* @returns {void}
174+
* @private
175+
*/
176+
function markFunctionReturnTypeAsUsed(node) {
177+
if (node.returnType) {
178+
markTypeAnnotationAsUsed(node.returnType);
179+
}
180+
}
181+
128182
//----------------------------------------------------------------------
129183
// Public
130184
//----------------------------------------------------------------------
131185
return {
186+
Identifier(node) {
187+
if (node.typeAnnotation) {
188+
markTypeAnnotationAsUsed(node.typeAnnotation);
189+
}
190+
},
191+
192+
TypeAnnotation(node) {
193+
if (node.typeAnnotation) {
194+
markTypeAnnotationAsUsed(node.typeAnnotation);
195+
}
196+
},
197+
198+
FunctionDeclaration: markFunctionReturnTypeAsUsed,
199+
FunctionExpression: markFunctionReturnTypeAsUsed,
200+
ArrowFunctionExpression: markFunctionReturnTypeAsUsed,
201+
132202
ClassProperty: markDecoratorsAsUsed,
133203
ClassDeclaration(node) {
134204
markDecoratorsAsUsed(node);

tests/lib/rules/no-unused-vars.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,98 @@ ruleTester.run("no-unused-vars", ruleNoUnusedVars, {
175175
"new Thing()"
176176
].join("\n"),
177177
parser
178+
},
179+
{
180+
code: [
181+
"interface Base {}",
182+
"const a: Base = {}",
183+
"console.log(a);"
184+
].join("\n"),
185+
parser
186+
},
187+
{
188+
code: [
189+
"import { Nullable } from 'nullable'",
190+
"const a: Nullable<string> = 'hello'",
191+
"console.log(a)"
192+
].join("\n"),
193+
parser
194+
},
195+
{
196+
code: [
197+
"import { Nullable } from 'nullable'",
198+
"import { SomeOther } from 'other'",
199+
"const a: Nullable<SomeOther> = 'hello'",
200+
"console.log(a)"
201+
].join("\n"),
202+
parser
203+
},
204+
{
205+
code: [
206+
"import { Nullable } from 'nullable'",
207+
"const a: Nullable | undefined = 'hello'",
208+
"console.log(a)"
209+
].join("\n"),
210+
parser
211+
},
212+
{
213+
code: [
214+
"import { Nullable } from 'nullable'",
215+
"const a: Nullable & undefined = 'hello'",
216+
"console.log(a)"
217+
].join("\n"),
218+
parser
219+
},
220+
{
221+
code: [
222+
"import { Nullable } from 'nullable'",
223+
"import { SomeOther } from 'other'",
224+
"const a: Nullable<SomeOther[]> = 'hello'",
225+
"console.log(a)"
226+
].join("\n"),
227+
parser
228+
},
229+
{
230+
code: [
231+
"import { Nullable } from 'nullable'",
232+
"import { SomeOther } from 'other'",
233+
"const a: Nullable<Array<SomeOther>> = 'hello'",
234+
"console.log(a)"
235+
].join("\n"),
236+
parser
237+
},
238+
{
239+
code: [
240+
"import { Nullable } from 'nullable'",
241+
"const a: Array<Nullable> = 'hello'",
242+
"console.log(a)"
243+
].join("\n"),
244+
parser
245+
},
246+
{
247+
code: [
248+
"import { Nullable } from 'nullable'",
249+
"const a: Array<Nullable[]> = 'hello'",
250+
"console.log(a)"
251+
].join("\n"),
252+
parser
253+
},
254+
{
255+
code: [
256+
"import { Nullable } from 'nullable'",
257+
"const a: Array<Array<Nullable>> = 'hello'",
258+
"console.log(a)"
259+
].join("\n"),
260+
parser
261+
},
262+
{
263+
code: [
264+
"import { Nullable } from 'nullable'",
265+
"import { SomeOther } from 'other'",
266+
"const a: Array<Nullable<SomeOther>> = 'hello'",
267+
"console.log(a)"
268+
].join("\n"),
269+
parser
178270
}
179271
],
180272

@@ -193,6 +285,37 @@ ruleTester.run("no-unused-vars", ruleNoUnusedVars, {
193285
column: 10
194286
}
195287
]
288+
},
289+
{
290+
code: [
291+
"import { Nullable } from 'nullable';",
292+
"const a: string = 'hello';",
293+
"console.log(a);"
294+
].join("\n"),
295+
parser,
296+
errors: [
297+
{
298+
message: "'Nullable' is defined but never used.",
299+
line: 1,
300+
column: 10
301+
}
302+
]
303+
},
304+
{
305+
code: [
306+
"import { Nullable } from 'nullable';",
307+
"import { SomeOther } from 'other';",
308+
"const a: Nullable<string> = 'hello';",
309+
"console.log(a);"
310+
].join("\n"),
311+
parser,
312+
errors: [
313+
{
314+
message: "'SomeOther' is defined but never used.",
315+
line: 2,
316+
column: 10
317+
}
318+
]
196319
}
197320
]
198321
});

0 commit comments

Comments
 (0)