@@ -42,6 +42,9 @@ namespace ts.codefix {
42
42
43
43
// Property declarations
44
44
Diagnostics . Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage . code ,
45
+
46
+ // Function expressions and declarations
47
+ Diagnostics . this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation . code ,
45
48
] ;
46
49
registerCodeFix ( {
47
50
errorCodes,
@@ -73,6 +76,8 @@ namespace ts.codefix {
73
76
case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code :
74
77
case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage . code :
75
78
return Diagnostics . Infer_parameter_types_from_usage ;
79
+ case Diagnostics . this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation . code :
80
+ return Diagnostics . Infer_this_type_of_0_from_usage ;
76
81
default :
77
82
return Diagnostics . Infer_type_of_0_from_usage ;
78
83
}
@@ -176,6 +181,14 @@ namespace ts.codefix {
176
181
}
177
182
return undefined ;
178
183
184
+ // Function 'this'
185
+ case Diagnostics . this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation . code :
186
+ if ( textChanges . isThisTypeAnnotatable ( containingFunction ) && markSeen ( containingFunction ) ) {
187
+ annotateThis ( changes , sourceFile , containingFunction , program , host , cancellationToken ) ;
188
+ return containingFunction ;
189
+ }
190
+ return undefined ;
191
+
179
192
default :
180
193
return Debug . fail ( String ( errorCode ) ) ;
181
194
}
@@ -191,7 +204,9 @@ namespace ts.codefix {
191
204
if ( ! isIdentifier ( parameterDeclaration . name ) ) {
192
205
return ;
193
206
}
194
- const parameterInferences = inferTypeForParametersFromUsage ( containingFunction , sourceFile , program , cancellationToken ) ||
207
+
208
+ const references = inferFunctionReferencesFromUsage ( containingFunction , sourceFile , program , cancellationToken ) ;
209
+ const parameterInferences = InferFromReference . inferTypeForParametersFromReferences ( references , containingFunction , program , cancellationToken ) ||
195
210
containingFunction . parameters . map < ParameterInference > ( p => ( {
196
211
declaration : p ,
197
212
type : isIdentifier ( p . name ) ? inferTypeForVariableFromUsage ( p . name , program , cancellationToken ) : program . getTypeChecker ( ) . getAnyType ( )
@@ -213,6 +228,36 @@ namespace ts.codefix {
213
228
}
214
229
}
215
230
231
+ function annotateThis ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , containingFunction : textChanges . ThisTypeAnnotatable , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) {
232
+ const references = inferFunctionReferencesFromUsage ( containingFunction , sourceFile , program , cancellationToken ) ;
233
+ if ( ! references ) {
234
+ return ;
235
+ }
236
+
237
+ const thisInference = InferFromReference . inferTypeForThisFromReferences ( references , program , cancellationToken ) ;
238
+ if ( ! thisInference ) {
239
+ return ;
240
+ }
241
+
242
+ const typeNode = getTypeNodeIfAccessible ( thisInference , containingFunction , program , host ) ;
243
+ if ( ! typeNode ) {
244
+ return ;
245
+ }
246
+
247
+ if ( isInJSFile ( containingFunction ) ) {
248
+ annotateJSDocThis ( changes , sourceFile , containingFunction , typeNode ) ;
249
+ }
250
+ else {
251
+ changes . tryInsertThisTypeAnnotation ( sourceFile , containingFunction , typeNode ) ;
252
+ }
253
+ }
254
+
255
+ function annotateJSDocThis ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , containingFunction : FunctionLike , typeNode : TypeNode ) {
256
+ addJSDocTags ( changes , sourceFile , containingFunction , [
257
+ createJSDocThisTag ( createJSDocTypeExpression ( typeNode ) ) ,
258
+ ] ) ;
259
+ }
260
+
216
261
function annotateSetAccessor ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , setAccessorDeclaration : SetAccessorDeclaration , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
217
262
const param = firstOrUndefined ( setAccessorDeclaration . parameters ) ;
218
263
if ( param && isIdentifier ( setAccessorDeclaration . name ) && isIdentifier ( param . name ) ) {
@@ -317,7 +362,7 @@ namespace ts.codefix {
317
362
return InferFromReference . unifyFromContext ( types , checker ) ;
318
363
}
319
364
320
- function inferTypeForParametersFromUsage ( containingFunction : FunctionLike , sourceFile : SourceFile , program : Program , cancellationToken : CancellationToken ) : ParameterInference [ ] | undefined {
365
+ function inferFunctionReferencesFromUsage ( containingFunction : FunctionLike , sourceFile : SourceFile , program : Program , cancellationToken : CancellationToken ) : ReadonlyArray < Identifier > | undefined {
321
366
let searchToken ;
322
367
switch ( containingFunction . kind ) {
323
368
case SyntaxKind . Constructor :
@@ -335,9 +380,12 @@ namespace ts.codefix {
335
380
searchToken = containingFunction . name ;
336
381
break ;
337
382
}
338
- if ( searchToken ) {
339
- return InferFromReference . inferTypeForParametersFromReferences ( getReferences ( searchToken , program , cancellationToken ) , containingFunction , program , cancellationToken ) ;
383
+
384
+ if ( ! searchToken ) {
385
+ return undefined ;
340
386
}
387
+
388
+ return getReferences ( searchToken , program , cancellationToken ) ;
341
389
}
342
390
343
391
interface ParameterInference {
@@ -364,6 +412,7 @@ namespace ts.codefix {
364
412
constructContexts ?: CallContext [ ] ;
365
413
numberIndexContext ?: UsageContext ;
366
414
stringIndexContext ?: UsageContext ;
415
+ candidateThisTypes ?: Type [ ] ;
367
416
}
368
417
369
418
export function inferTypesFromReferences ( references : ReadonlyArray < Identifier > , checker : TypeChecker , cancellationToken : CancellationToken ) : Type [ ] {
@@ -375,15 +424,12 @@ namespace ts.codefix {
375
424
return inferFromContext ( usageContext , checker ) ;
376
425
}
377
426
378
- export function inferTypeForParametersFromReferences ( references : ReadonlyArray < Identifier > , declaration : FunctionLike , program : Program , cancellationToken : CancellationToken ) : ParameterInference [ ] | undefined {
379
- const checker = program . getTypeChecker ( ) ;
380
- if ( references . length === 0 ) {
381
- return undefined ;
382
- }
383
- if ( ! declaration . parameters ) {
427
+ export function inferTypeForParametersFromReferences ( references : ReadonlyArray < Identifier > | undefined , declaration : FunctionLike , program : Program , cancellationToken : CancellationToken ) : ParameterInference [ ] | undefined {
428
+ if ( references === undefined || references . length === 0 || ! declaration . parameters ) {
384
429
return undefined ;
385
430
}
386
431
432
+ const checker = program . getTypeChecker ( ) ;
387
433
const usageContext : UsageContext = { } ;
388
434
for ( const reference of references ) {
389
435
cancellationToken . throwIfCancellationRequested ( ) ;
@@ -421,6 +467,22 @@ namespace ts.codefix {
421
467
} ) ;
422
468
}
423
469
470
+ export function inferTypeForThisFromReferences ( references : ReadonlyArray < Identifier > , program : Program , cancellationToken : CancellationToken ) {
471
+ if ( references . length === 0 ) {
472
+ return undefined ;
473
+ }
474
+
475
+ const checker = program . getTypeChecker ( ) ;
476
+ const usageContext : UsageContext = { } ;
477
+
478
+ for ( const reference of references ) {
479
+ cancellationToken . throwIfCancellationRequested ( ) ;
480
+ inferTypeFromContext ( reference , checker , usageContext ) ;
481
+ }
482
+
483
+ return unifyFromContext ( usageContext . candidateThisTypes || emptyArray , checker ) ;
484
+ }
485
+
424
486
function inferTypeFromContext ( node : Expression , checker : TypeChecker , usageContext : UsageContext ) : void {
425
487
while ( isRightSideOfQualifiedNameOrPropertyAccess ( node ) ) {
426
488
node = < Expression > node . parent ;
@@ -455,6 +517,13 @@ namespace ts.codefix {
455
517
case SyntaxKind . ElementAccessExpression :
456
518
inferTypeFromPropertyElementExpressionContext ( < ElementAccessExpression > node . parent , node , checker , usageContext ) ;
457
519
break ;
520
+ case SyntaxKind . PropertyAssignment :
521
+ case SyntaxKind . ShorthandPropertyAssignment :
522
+ inferTypeFromPropertyAssignment ( < PropertyAssignment | ShorthandPropertyAssignment > node . parent , checker , usageContext ) ;
523
+ break ;
524
+ case SyntaxKind . PropertyDeclaration :
525
+ inferTypeFromPropertyDeclaration ( < PropertyDeclaration > node . parent , checker , usageContext ) ;
526
+ break ;
458
527
case SyntaxKind . VariableDeclaration : {
459
528
const { name, initializer } = node . parent as VariableDeclaration ;
460
529
if ( node === name ) {
@@ -647,6 +716,21 @@ namespace ts.codefix {
647
716
}
648
717
}
649
718
719
+ function inferTypeFromPropertyAssignment ( assignment : PropertyAssignment | ShorthandPropertyAssignment , checker : TypeChecker , usageContext : UsageContext ) {
720
+ const objectLiteral = isShorthandPropertyAssignment ( assignment ) ?
721
+ assignment . parent :
722
+ assignment . parent . parent ;
723
+ const nodeWithRealType = isVariableDeclaration ( objectLiteral . parent ) ?
724
+ objectLiteral . parent :
725
+ objectLiteral ;
726
+
727
+ addCandidateThisType ( usageContext , checker . getTypeAtLocation ( nodeWithRealType ) ) ;
728
+ }
729
+
730
+ function inferTypeFromPropertyDeclaration ( declaration : PropertyDeclaration , checker : TypeChecker , usageContext : UsageContext ) {
731
+ addCandidateThisType ( usageContext , checker . getTypeAtLocation ( declaration . parent ) ) ;
732
+ }
733
+
650
734
interface Priority {
651
735
high : ( t : Type ) => boolean ;
652
736
low : ( t : Type ) => boolean ;
@@ -841,6 +925,12 @@ namespace ts.codefix {
841
925
}
842
926
}
843
927
928
+ function addCandidateThisType ( context : UsageContext , type : Type | undefined ) {
929
+ if ( type && ! ( type . flags & TypeFlags . Any ) && ! ( type . flags & TypeFlags . Never ) ) {
930
+ ( context . candidateThisTypes || ( context . candidateThisTypes = [ ] ) ) . push ( type ) ;
931
+ }
932
+ }
933
+
844
934
function hasCallContext ( usageContext : UsageContext | undefined ) : boolean {
845
935
return ! ! usageContext && ! ! usageContext . callContexts ;
846
936
}
0 commit comments