@@ -285,7 +285,7 @@ namespace ts.codefix {
285285 if ( isCallExpression ( node ) && hasPropertyAccessExpressionWithName ( node , "then" ) && nodeType && ! ! transformer . checker . getPromisedTypeOfPromise ( nodeType ) ) {
286286 return transformThen ( node , transformer , outermostParent , prevArgName ) ;
287287 }
288- else if ( isCallExpression ( node ) && hasPropertyAccessExpressionWithName ( node , "catch" ) && nodeType && ! ! transformer . checker . getPromisedTypeOfPromise ( nodeType ) && ( ! prevArgName || "identifier" in prevArgName ) ) {
288+ else if ( isCallExpression ( node ) && hasPropertyAccessExpressionWithName ( node , "catch" ) && nodeType && ! ! transformer . checker . getPromisedTypeOfPromise ( nodeType ) ) {
289289 return transformCatch ( node , transformer , prevArgName ) ;
290290 }
291291 else if ( isPropertyAccessExpression ( node ) ) {
@@ -299,52 +299,67 @@ namespace ts.codefix {
299299 return emptyArray ;
300300 }
301301
302- function transformCatch ( node : CallExpression , transformer : Transformer , prevArgName ?: SynthIdentifier ) : ReadonlyArray < Statement > {
302+ function transformCatch ( node : CallExpression , transformer : Transformer , prevArgName ?: SynthBindingName ) : ReadonlyArray < Statement > {
303303 const func = node . arguments [ 0 ] ;
304304 const argName = getArgBindingName ( func , transformer ) ;
305305 const shouldReturn = transformer . setOfExpressionsToReturn . get ( getNodeId ( node ) . toString ( ) ) ;
306+ let possibleNameForVarDecl : SynthIdentifier | undefined ;
306307
307308 /*
308309 If there is another call in the chain after the .catch() we are transforming, we will need to save the result of both paths (try block and catch block)
309310 To do this, we will need to synthesize a variable that we were not aware of while we were adding identifiers to the synthNamesMap
310311 We will use the prevArgName and then update the synthNamesMap with a new variable name for the next transformation step
311312 */
312313 if ( prevArgName && ! shouldReturn ) {
313- prevArgName . numberOfAssignmentsOriginal = 2 ; // Try block and catch block
314- transformer . synthNamesMap . forEach ( ( val , key ) => {
315- if ( val . identifier . text === prevArgName . identifier . text ) {
316- const newSynthName = createUniqueSynthName ( prevArgName ) ;
317- transformer . synthNamesMap . set ( key , newSynthName ) ;
318- }
319- } ) ;
314+ if ( isSynthIdentifier ( prevArgName ) ) {
315+ possibleNameForVarDecl = prevArgName ;
316+ transformer . synthNamesMap . forEach ( ( val , key ) => {
317+ if ( val . identifier . text === prevArgName . identifier . text ) {
318+ const newSynthName = createUniqueSynthName ( prevArgName ) ;
319+ transformer . synthNamesMap . set ( key , newSynthName ) ;
320+ }
321+ } ) ;
322+ }
323+ else {
324+ possibleNameForVarDecl = createUniqueSynthName ( {
325+ identifier : createOptimisticUniqueName ( "result" ) ,
326+ types : prevArgName . types ,
327+ numberOfAssignmentsOriginal : 0
328+ } ) ;
329+ }
320330
331+ possibleNameForVarDecl . numberOfAssignmentsOriginal = 2 ; // Try block and catch block
321332 // update the constIdentifiers list
322- if ( transformer . constIdentifiers . some ( elem => elem . text === prevArgName . identifier . text ) ) {
323- transformer . constIdentifiers . push ( createUniqueSynthName ( prevArgName ) . identifier ) ;
333+ if ( transformer . constIdentifiers . some ( elem => elem . text === possibleNameForVarDecl ! . identifier . text ) ) {
334+ transformer . constIdentifiers . push ( createUniqueSynthName ( possibleNameForVarDecl ) . identifier ) ;
324335 }
325336 }
326337
327- const tryBlock = createBlock ( transformExpression ( node . expression , transformer , node , prevArgName ) ) ;
338+ const tryBlock = createBlock ( transformExpression ( node . expression , transformer , node , possibleNameForVarDecl ) ) ;
328339
329- const transformationBody = getTransformationBody ( func , prevArgName , argName , node , transformer ) ;
330- const catchArg = argName ? "identifier" in argName ? argName . identifier . text : argName . bindingPattern : "e" ;
340+ const transformationBody = getTransformationBody ( func , possibleNameForVarDecl , argName , node , transformer ) ;
341+ const catchArg = argName ? isSynthIdentifier ( argName ) ? argName . identifier . text : argName . bindingPattern : "e" ;
331342 const catchVariableDeclaration = createVariableDeclaration ( catchArg ) ;
332343 const catchClause = createCatchClause ( catchVariableDeclaration , createBlock ( transformationBody ) ) ;
333344
334345 /*
335346 In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block)
336347 */
337- let varDeclList ;
338- if ( prevArgName && ! shouldReturn ) {
339- const typeArray : Type [ ] = prevArgName . types ;
348+ let varDeclList : VariableStatement | undefined ;
349+ let varDeclIdentifier : Identifier | undefined ;
350+ if ( possibleNameForVarDecl && ! shouldReturn ) {
351+ varDeclIdentifier = getSynthesizedDeepClone ( possibleNameForVarDecl . identifier ) ;
352+ const typeArray : Type [ ] = possibleNameForVarDecl . types ;
340353 const unionType = transformer . checker . getUnionType ( typeArray , UnionReduction . Subtype ) ;
341354 const unionTypeNode = transformer . isInJSFile ? undefined : transformer . checker . typeToTypeNode ( unionType ) ;
342- const varDecl = [ createVariableDeclaration ( getSynthesizedDeepClone ( prevArgName . identifier ) , unionTypeNode ) ] ;
355+ const varDecl = [ createVariableDeclaration ( varDeclIdentifier , unionTypeNode ) ] ;
343356 varDeclList = createVariableStatement ( /*modifiers*/ undefined , createVariableDeclarationList ( varDecl , NodeFlags . Let ) ) ;
344357 }
345358
346359 const tryStatement = createTry ( tryBlock , catchClause , /*finallyBlock*/ undefined ) ;
347- return varDeclList ? [ varDeclList , tryStatement ] : [ tryStatement ] ;
360+ const destructuredResult = prevArgName && varDeclIdentifier && isSynthBindingPattern ( prevArgName )
361+ && createVariableStatement ( /* modifiers */ undefined , createVariableDeclarationList ( [ createVariableDeclaration ( getSynthesizedDeepCloneWithRenames ( prevArgName . bindingPattern ) , /* type */ undefined , varDeclIdentifier ) ] , NodeFlags . Const ) ) ;
362+ return compact ( [ varDeclList , tryStatement , destructuredResult ] ) ;
348363 }
349364
350365 function getIdentifierTextsFromBindingName ( bindingName : BindingName ) : ReadonlyArray < string > {
@@ -355,7 +370,7 @@ namespace ts.codefix {
355370 } ) ;
356371 }
357372
358- function createUniqueSynthName ( prevArgName : SynthIdentifier ) {
373+ function createUniqueSynthName ( prevArgName : SynthIdentifier ) : SynthIdentifier {
359374 const renamedPrevArg = createOptimisticUniqueName ( prevArgName . identifier . text ) ;
360375 const newSynthName = { identifier : renamedPrevArg , types : [ ] , numberOfAssignmentsOriginal : 0 } ;
361376 return newSynthName ;
@@ -378,7 +393,7 @@ namespace ts.codefix {
378393
379394 const transformationBody2 = getTransformationBody ( rej , prevArgName , argNameRej , node , transformer ) ;
380395
381- const catchArg = argNameRej ? "identifier" in argNameRej ? argNameRej . identifier . text : argNameRej . bindingPattern : "e" ;
396+ const catchArg = argNameRej ? isSynthIdentifier ( argNameRej ) ? argNameRej . identifier . text : argNameRej . bindingPattern : "e" ;
382397 const catchVariableDeclaration = createVariableDeclaration ( catchArg ) ;
383398 const catchClause = createCatchClause ( catchVariableDeclaration , createBlock ( transformationBody2 ) ) ;
384399
@@ -414,7 +429,7 @@ namespace ts.codefix {
414429 return [ createStatement ( rightHandSide ) ] ;
415430 }
416431
417- if ( "identifier" in prevArgName && prevArgName . types . length < prevArgName . numberOfAssignmentsOriginal ) {
432+ if ( isSynthIdentifier ( prevArgName ) && prevArgName . types . length < prevArgName . numberOfAssignmentsOriginal ) {
418433 // if the variable has already been declared, we don't need "let" or "const"
419434 return [ createStatement ( createAssignment ( getSynthesizedDeepClone ( prevArgName . identifier ) , rightHandSide ) ) ] ;
420435 }
@@ -437,7 +452,7 @@ namespace ts.codefix {
437452 break ;
438453 }
439454
440- const synthCall = createCall ( getSynthesizedDeepClone ( func as Identifier ) , /*typeArguments*/ undefined , "identifier" in argName ? [ argName . identifier ] : [ ] ) ;
455+ const synthCall = createCall ( getSynthesizedDeepClone ( func as Identifier ) , /*typeArguments*/ undefined , isSynthIdentifier ( argName ) ? [ argName . identifier ] : [ ] ) ;
441456 if ( shouldReturn ) {
442457 return [ createReturn ( synthCall ) ] ;
443458 }
@@ -631,13 +646,21 @@ namespace ts.codefix {
631646 if ( ! bindingName ) {
632647 return true ;
633648 }
634- if ( "identifier" in bindingName ) {
649+ if ( isSynthIdentifier ( bindingName ) ) {
635650 return ! bindingName . identifier . text ;
636651 }
637652 return every ( bindingName . elements , isEmpty ) ;
638653 }
639654
640655 function getNode ( bindingName : SynthBindingName ) {
641- return "identifier" in bindingName ? bindingName . identifier : bindingName . bindingPattern ;
656+ return isSynthIdentifier ( bindingName ) ? bindingName . identifier : bindingName . bindingPattern ;
657+ }
658+
659+ function isSynthIdentifier ( bindingName : SynthBindingName ) : bindingName is SynthIdentifier {
660+ return "identifier" in bindingName ;
661+ }
662+
663+ function isSynthBindingPattern ( bindingName : SynthBindingName ) : bindingName is SynthBindingPattern {
664+ return "elements" in bindingName ;
642665 }
643666}
0 commit comments