@@ -21,6 +21,27 @@ namespace ts.codefix {
21
21
22
22
// Property declarations
23
23
Diagnostics . Member_0_implicitly_has_an_1_type . code ,
24
+
25
+ //// Suggestions
26
+ // Variable declarations
27
+ Diagnostics . Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage . code ,
28
+
29
+ // Variable uses
30
+ Diagnostics . Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code ,
31
+
32
+ // Parameter declarations
33
+ Diagnostics . Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code ,
34
+ Diagnostics . Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage . code ,
35
+
36
+ // Get Accessor declarations
37
+ Diagnostics . Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage . code ,
38
+ Diagnostics . _0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage . code ,
39
+
40
+ // Set Accessor declarations
41
+ Diagnostics . Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage . code ,
42
+
43
+ // Property declarations
44
+ Diagnostics . Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code ,
24
45
] ;
25
46
registerCodeFix ( {
26
47
errorCodes,
@@ -47,20 +68,46 @@ namespace ts.codefix {
47
68
function getDiagnostic ( errorCode : number , token : Node ) : DiagnosticMessage {
48
69
switch ( errorCode ) {
49
70
case Diagnostics . Parameter_0_implicitly_has_an_1_type . code :
71
+ case Diagnostics . Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code :
50
72
return isSetAccessorDeclaration ( getContainingFunction ( token ) ! ) ? Diagnostics . Infer_type_of_0_from_usage : Diagnostics . Infer_parameter_types_from_usage ; // TODO: GH#18217
51
73
case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code :
74
+ case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage . code :
52
75
return Diagnostics . Infer_parameter_types_from_usage ;
53
76
default :
54
77
return Diagnostics . Infer_type_of_0_from_usage ;
55
78
}
56
79
}
57
80
81
+ /** Map suggestion code to error code */
82
+ function mapSuggestionDiagnostic ( errorCode : number ) {
83
+ switch ( errorCode ) {
84
+ case Diagnostics . Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage . code :
85
+ return Diagnostics . Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined . code ;
86
+ case Diagnostics . Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code :
87
+ return Diagnostics . Variable_0_implicitly_has_an_1_type . code ;
88
+ case Diagnostics . Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code :
89
+ return Diagnostics . Parameter_0_implicitly_has_an_1_type . code ;
90
+ case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage . code :
91
+ return Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code ;
92
+ case Diagnostics . Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage . code :
93
+ return Diagnostics . Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation . code ;
94
+ case Diagnostics . _0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage . code :
95
+ return Diagnostics . _0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type . code ;
96
+ case Diagnostics . Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage . code :
97
+ return Diagnostics . Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation . code ;
98
+ case Diagnostics . Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code :
99
+ return Diagnostics . Member_0_implicitly_has_an_1_type . code ;
100
+ }
101
+ return errorCode ;
102
+ }
103
+
58
104
function doChange ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , token : Node , errorCode : number , program : Program , cancellationToken : CancellationToken , markSeen : NodeSeenTracker , host : LanguageServiceHost ) : Declaration | undefined {
59
105
if ( ! isParameterPropertyModifier ( token . kind ) && token . kind !== SyntaxKind . Identifier && token . kind !== SyntaxKind . DotDotDotToken && token . kind !== SyntaxKind . ThisKeyword ) {
60
106
return undefined ;
61
107
}
62
108
63
109
const { parent } = token ;
110
+ errorCode = mapSuggestionDiagnostic ( errorCode ) ;
64
111
switch ( errorCode ) {
65
112
// Variable and Property declarations
66
113
case Diagnostics . Member_0_implicitly_has_an_1_type . code :
@@ -71,7 +118,7 @@ namespace ts.codefix {
71
118
}
72
119
if ( isPropertyAccessExpression ( parent ) ) {
73
120
const type = inferTypeForVariableFromUsage ( parent . name , program , cancellationToken ) ;
74
- const typeNode = type && getTypeNodeIfAccessible ( type , parent , program , host ) ;
121
+ const typeNode = getTypeNodeIfAccessible ( type , parent , program , host ) ;
75
122
if ( typeNode ) {
76
123
// Note that the codefix will never fire with an existing `@type` tag, so there is no need to merge tags
77
124
const typeTag = createJSDocTypeTag ( createJSDocTypeExpression ( typeNode ) , /*comment*/ "" ) ;
@@ -107,7 +154,7 @@ namespace ts.codefix {
107
154
case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code :
108
155
if ( markSeen ( containingFunction ) ) {
109
156
const param = cast ( parent , isParameter ) ;
110
- annotateParameters ( changes , param , containingFunction , sourceFile , program , host , cancellationToken ) ;
157
+ annotateParameters ( changes , sourceFile , param , containingFunction , program , host , cancellationToken ) ;
111
158
return param ;
112
159
}
113
160
return undefined ;
@@ -152,15 +199,15 @@ namespace ts.codefix {
152
199
return false ;
153
200
}
154
201
155
- function annotateParameters ( changes : textChanges . ChangeTracker , parameterDeclaration : ParameterDeclaration , containingFunction : FunctionLike , sourceFile : SourceFile , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
202
+ function annotateParameters ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , parameterDeclaration : ParameterDeclaration , containingFunction : FunctionLike , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
156
203
if ( ! isIdentifier ( parameterDeclaration . name ) || ! isApplicableFunctionForInference ( containingFunction ) ) {
157
204
return ;
158
205
}
159
206
160
207
const parameterInferences = inferTypeForParametersFromUsage ( containingFunction , sourceFile , program , cancellationToken ) ||
161
208
containingFunction . parameters . map < ParameterInference > ( p => ( {
162
209
declaration : p ,
163
- type : isIdentifier ( p . name ) ? inferTypeForVariableFromUsage ( p . name , program , cancellationToken ) : undefined
210
+ type : isIdentifier ( p . name ) ? inferTypeForVariableFromUsage ( p . name , program , cancellationToken ) : program . getTypeChecker ( ) . getAnyType ( )
164
211
} ) ) ;
165
212
Debug . assert ( containingFunction . parameters . length === parameterInferences . length ) ;
166
213
@@ -179,8 +226,10 @@ namespace ts.codefix {
179
226
function annotateSetAccessor ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , setAccessorDeclaration : SetAccessorDeclaration , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
180
227
const param = firstOrUndefined ( setAccessorDeclaration . parameters ) ;
181
228
if ( param && isIdentifier ( setAccessorDeclaration . name ) && isIdentifier ( param . name ) ) {
182
- const type = inferTypeForVariableFromUsage ( setAccessorDeclaration . name , program , cancellationToken ) ||
183
- inferTypeForVariableFromUsage ( param . name , program , cancellationToken ) ;
229
+ let type = inferTypeForVariableFromUsage ( setAccessorDeclaration . name , program , cancellationToken ) ;
230
+ if ( type === program . getTypeChecker ( ) . getAnyType ( ) ) {
231
+ type = inferTypeForVariableFromUsage ( param . name , program , cancellationToken ) ;
232
+ }
184
233
if ( isInJSFile ( setAccessorDeclaration ) ) {
185
234
annotateJSDocParameters ( changes , sourceFile , [ { declaration : param , type } ] , program , host ) ;
186
235
}
@@ -190,8 +239,8 @@ namespace ts.codefix {
190
239
}
191
240
}
192
241
193
- function annotate ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , declaration : textChanges . TypeAnnotatable , type : Type | undefined , program : Program , host : LanguageServiceHost ) : void {
194
- const typeNode = type && getTypeNodeIfAccessible ( type , declaration , program , host ) ;
242
+ function annotate ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , declaration : textChanges . TypeAnnotatable , type : Type , program : Program , host : LanguageServiceHost ) : void {
243
+ const typeNode = getTypeNodeIfAccessible ( type , declaration , program , host ) ;
195
244
if ( typeNode ) {
196
245
if ( isInJSFile ( sourceFile ) && declaration . kind !== SyntaxKind . PropertySignature ) {
197
246
const parent = isVariableDeclaration ( declaration ) ? tryCast ( declaration . parent . parent , isVariableStatement ) : declaration ;
@@ -285,7 +334,7 @@ namespace ts.codefix {
285
334
entry . kind !== FindAllReferences . EntryKind . Span ? tryCast ( entry . node , isIdentifier ) : undefined ) ;
286
335
}
287
336
288
- function inferTypeForVariableFromUsage ( token : Identifier , program : Program , cancellationToken : CancellationToken ) : Type | undefined {
337
+ function inferTypeForVariableFromUsage ( token : Identifier , program : Program , cancellationToken : CancellationToken ) : Type {
289
338
return InferFromReference . inferTypeFromReferences ( getReferences ( token , program , cancellationToken ) , program . getTypeChecker ( ) , cancellationToken ) ;
290
339
}
291
340
@@ -307,7 +356,7 @@ namespace ts.codefix {
307
356
308
357
interface ParameterInference {
309
358
readonly declaration : ParameterDeclaration ;
310
- readonly type ? : Type ;
359
+ readonly type : Type ;
311
360
readonly isOptional ?: boolean ;
312
361
}
313
362
@@ -329,13 +378,13 @@ namespace ts.codefix {
329
378
stringIndexContext ?: UsageContext ;
330
379
}
331
380
332
- export function inferTypeFromReferences ( references : ReadonlyArray < Identifier > , checker : TypeChecker , cancellationToken : CancellationToken ) : Type | undefined {
381
+ export function inferTypeFromReferences ( references : ReadonlyArray < Identifier > , checker : TypeChecker , cancellationToken : CancellationToken ) : Type {
333
382
const usageContext : UsageContext = { } ;
334
383
for ( const reference of references ) {
335
384
cancellationToken . throwIfCancellationRequested ( ) ;
336
385
inferTypeFromContext ( reference , checker , usageContext ) ;
337
386
}
338
- return getTypeFromUsageContext ( usageContext , checker ) ;
387
+ return getTypeFromUsageContext ( usageContext , checker ) || checker . getAnyType ( ) ;
339
388
}
340
389
341
390
export function inferTypeForParametersFromReferences ( references : ReadonlyArray < Identifier > , declaration : FunctionLikeDeclaration , checker : TypeChecker , cancellationToken : CancellationToken ) : ParameterInference [ ] | undefined {
@@ -374,7 +423,7 @@ namespace ts.codefix {
374
423
}
375
424
}
376
425
if ( ! types . length ) {
377
- return { declaration : parameter } ;
426
+ return { declaration : parameter , type : checker . getAnyType ( ) } ;
378
427
}
379
428
const type = checker . getWidenedType ( checker . getUnionType ( types , UnionReduction . Subtype ) ) ;
380
429
return {
0 commit comments