namespace ts . refactor . inferFunctionReturnType { const refactorName = "Infer function return type" ; const refactorDescription = Diagnostics . Infer_function_return_type . message ; const inferReturnTypeAction = { name : refactorName , description : refactorDescription , kind : "refactor.rewrite.function.returnType" } ; registerRefactor ( refactorName , { kinds : [ inferReturnTypeAction . kind ] , getEditsForAction : getRefactorEditsToInferReturnType , getAvailableActions : getRefactorActionsToInferReturnType } ) ; function getRefactorEditsToInferReturnType ( context ) { const info = getInfo ( context ) ; if ( info && ! isRefactorErrorInfo ( info ) ) { const edits = textChanges . ChangeTracker . with ( context , t => doChange ( context . file , t , info . declaration , info . returnTypeNode ) ) ; return { renameFilename : undefined , renameLocation : undefined , edits } ; } return undefined ; } function getRefactorActionsToInferReturnType ( context ) { const info = getInfo ( context ) ; if ( ! info ) return emptyArray ; if ( ! isRefactorErrorInfo ( info ) ) { return [ { name : refactorName , description : refactorDescription , actions : [ inferReturnTypeAction ] } ] ; } if ( context . preferences . provideRefactorNotApplicableReason ) { return [ { name : refactorName , description : refactorDescription , actions : [ { ... inferReturnTypeAction , notApplicableReason : info . error } ] } ] ; } return emptyArray ; } type ConvertibleDeclaration = FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration ; interface FunctionInfo { declaration : ConvertibleDeclaration ; returnTypeNode : TypeNode ; } function doChange ( sourceFile , changes , declaration , typeNode ) { const closeParen = findChildOfKind ( declaration , SyntaxKind . CloseParenToken , sourceFile ) ; const needParens = isArrowFunction ( declaration ) && closeParen === undefined ; const endNode = needParens ? first ( declaration . parameters ) : closeParen ; if ( endNode ) { if ( needParens ) { changes . insertNodeBefore ( sourceFile , endNode , factory . createToken ( SyntaxKind . OpenParenToken ) ) ; changes . insertNodeAfter ( sourceFile , endNode , factory . createToken ( SyntaxKind . CloseParenToken ) ) ; } changes . insertNodeAt ( sourceFile , endNode . end , typeNode , { prefix : ": " } ) ; } } function getInfo ( context ) { if ( isInJSFile ( context . file ) || ! refactorKindBeginsWith ( inferReturnTypeAction . kind , context . kind ) ) return ; const token = getTokenAtPosition ( context . file , context . startPosition ) ; const declaration = findAncestor ( token , n => isBlock ( n ) || n . parent && isArrowFunction ( n . parent ) && ( n . kind === SyntaxKind . EqualsGreaterThanToken || n . parent . body === n ) ? "quit" : isConvertibleDeclaration ( n ) ) as ConvertibleDeclaration | undefined ; if ( ! declaration || ! declaration . body || declaration . type ) { return { error : getLocaleSpecificMessage ( Diagnostics . Return_type_must_be_inferred_from_a_function ) } ; } const typeChecker = context . program . getTypeChecker ( ) ; const returnType = tryGetReturnType ( typeChecker , declaration ) ; if ( ! returnType ) { return { error : getLocaleSpecificMessage ( Diagnostics . Could_not_determine_function_return_type ) } ; } const returnTypeNode = typeChecker . typeToTypeNode ( returnType , declaration , NodeBuilderFlags . NoTruncation ) ; if ( returnTypeNode ) { return { declaration , returnTypeNode } ; } } function isConvertibleDeclaration ( node ) { switch ( node . kind ) { case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : case SyntaxKind . MethodDeclaration : return true ; default : return false ; } } function tryGetReturnType ( typeChecker , node ) { if ( typeChecker . isImplementationOfOverload ( node ) ) { const signatures = typeChecker . getTypeAtLocation ( node ) . getCallSignatures ( ) ; if ( signatures . length > 1 ) { return typeChecker . getUnionType ( mapDefined ( signatures , s => s . getReturnType ( ) ) ) ; } } const signature = typeChecker . getSignatureFromDeclaration ( node ) ; if ( signature ) { return typeChecker . getReturnTypeOfSignature ( signature ) ; } } }