@@ -21,6 +21,27 @@ namespace ts.codefix {
2121
2222 // Property declarations
2323 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 ,
2445 ] ;
2546 registerCodeFix ( {
2647 errorCodes,
@@ -47,20 +68,46 @@ namespace ts.codefix {
4768 function getDiagnostic ( errorCode : number , token : Node ) : DiagnosticMessage {
4869 switch ( errorCode ) {
4970 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 :
5072 return isSetAccessorDeclaration ( getContainingFunction ( token ) ! ) ? Diagnostics . Infer_type_of_0_from_usage : Diagnostics . Infer_parameter_types_from_usage ; // TODO: GH#18217
5173 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 :
5275 return Diagnostics . Infer_parameter_types_from_usage ;
5376 default :
5477 return Diagnostics . Infer_type_of_0_from_usage ;
5578 }
5679 }
5780
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+
58104 function doChange ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , token : Node , errorCode : number , program : Program , cancellationToken : CancellationToken , markSeen : NodeSeenTracker , host : LanguageServiceHost ) : Declaration | undefined {
59105 if ( ! isParameterPropertyModifier ( token . kind ) && token . kind !== SyntaxKind . Identifier && token . kind !== SyntaxKind . DotDotDotToken && token . kind !== SyntaxKind . ThisKeyword ) {
60106 return undefined ;
61107 }
62108
63109 const { parent } = token ;
110+ errorCode = mapSuggestionDiagnostic ( errorCode ) ;
64111 switch ( errorCode ) {
65112 // Variable and Property declarations
66113 case Diagnostics . Member_0_implicitly_has_an_1_type . code :
@@ -71,7 +118,7 @@ namespace ts.codefix {
71118 }
72119 if ( isPropertyAccessExpression ( parent ) ) {
73120 const type = inferTypeForVariableFromUsage ( parent . name , program , cancellationToken ) ;
74- const typeNode = type && getTypeNodeIfAccessible ( type , parent , program , host ) ;
121+ const typeNode = getTypeNodeIfAccessible ( type , parent , program , host ) ;
75122 if ( typeNode ) {
76123 // Note that the codefix will never fire with an existing `@type` tag, so there is no need to merge tags
77124 const typeTag = createJSDocTypeTag ( createJSDocTypeExpression ( typeNode ) , /*comment*/ "" ) ;
@@ -107,7 +154,7 @@ namespace ts.codefix {
107154 case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code :
108155 if ( markSeen ( containingFunction ) ) {
109156 const param = cast ( parent , isParameter ) ;
110- annotateParameters ( changes , param , containingFunction , sourceFile , program , host , cancellationToken ) ;
157+ annotateParameters ( changes , sourceFile , param , containingFunction , program , host , cancellationToken ) ;
111158 return param ;
112159 }
113160 return undefined ;
@@ -152,15 +199,15 @@ namespace ts.codefix {
152199 return false ;
153200 }
154201
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 {
156203 if ( ! isIdentifier ( parameterDeclaration . name ) || ! isApplicableFunctionForInference ( containingFunction ) ) {
157204 return ;
158205 }
159206
160207 const parameterInferences = inferTypeForParametersFromUsage ( containingFunction , sourceFile , program , cancellationToken ) ||
161208 containingFunction . parameters . map < ParameterInference > ( p => ( {
162209 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 ( )
164211 } ) ) ;
165212 Debug . assert ( containingFunction . parameters . length === parameterInferences . length ) ;
166213
@@ -179,8 +226,10 @@ namespace ts.codefix {
179226 function annotateSetAccessor ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , setAccessorDeclaration : SetAccessorDeclaration , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
180227 const param = firstOrUndefined ( setAccessorDeclaration . parameters ) ;
181228 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+ }
184233 if ( isInJSFile ( setAccessorDeclaration ) ) {
185234 annotateJSDocParameters ( changes , sourceFile , [ { declaration : param , type } ] , program , host ) ;
186235 }
@@ -190,8 +239,8 @@ namespace ts.codefix {
190239 }
191240 }
192241
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 ) ;
195244 if ( typeNode ) {
196245 if ( isInJSFile ( sourceFile ) && declaration . kind !== SyntaxKind . PropertySignature ) {
197246 const parent = isVariableDeclaration ( declaration ) ? tryCast ( declaration . parent . parent , isVariableStatement ) : declaration ;
@@ -285,7 +334,7 @@ namespace ts.codefix {
285334 entry . kind !== FindAllReferences . EntryKind . Span ? tryCast ( entry . node , isIdentifier ) : undefined ) ;
286335 }
287336
288- function inferTypeForVariableFromUsage ( token : Identifier , program : Program , cancellationToken : CancellationToken ) : Type | undefined {
337+ function inferTypeForVariableFromUsage ( token : Identifier , program : Program , cancellationToken : CancellationToken ) : Type {
289338 return InferFromReference . inferTypeFromReferences ( getReferences ( token , program , cancellationToken ) , program . getTypeChecker ( ) , cancellationToken ) ;
290339 }
291340
@@ -307,7 +356,7 @@ namespace ts.codefix {
307356
308357 interface ParameterInference {
309358 readonly declaration : ParameterDeclaration ;
310- readonly type ? : Type ;
359+ readonly type : Type ;
311360 readonly isOptional ?: boolean ;
312361 }
313362
@@ -329,13 +378,13 @@ namespace ts.codefix {
329378 stringIndexContext ?: UsageContext ;
330379 }
331380
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 {
333382 const usageContext : UsageContext = { } ;
334383 for ( const reference of references ) {
335384 cancellationToken . throwIfCancellationRequested ( ) ;
336385 inferTypeFromContext ( reference , checker , usageContext ) ;
337386 }
338- return getTypeFromUsageContext ( usageContext , checker ) ;
387+ return getTypeFromUsageContext ( usageContext , checker ) || checker . getAnyType ( ) ;
339388 }
340389
341390 export function inferTypeForParametersFromReferences ( references : ReadonlyArray < Identifier > , declaration : FunctionLikeDeclaration , checker : TypeChecker , cancellationToken : CancellationToken ) : ParameterInference [ ] | undefined {
@@ -374,7 +423,7 @@ namespace ts.codefix {
374423 }
375424 }
376425 if ( ! types . length ) {
377- return { declaration : parameter } ;
426+ return { declaration : parameter , type : checker . getAnyType ( ) } ;
378427 }
379428 const type = checker . getWidenedType ( checker . getUnionType ( types , UnionReduction . Subtype ) ) ;
380429 return {
0 commit comments