@@ -285,7 +285,7 @@ namespace ts.codefix {
285
285
if ( isCallExpression ( node ) && hasPropertyAccessExpressionWithName ( node , "then" ) && nodeType && ! ! transformer . checker . getPromisedTypeOfPromise ( nodeType ) ) {
286
286
return transformThen ( node , transformer , outermostParent , prevArgName ) ;
287
287
}
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 ) ) {
289
289
return transformCatch ( node , transformer , prevArgName ) ;
290
290
}
291
291
else if ( isPropertyAccessExpression ( node ) ) {
@@ -299,52 +299,67 @@ namespace ts.codefix {
299
299
return emptyArray ;
300
300
}
301
301
302
- function transformCatch ( node : CallExpression , transformer : Transformer , prevArgName ?: SynthIdentifier ) : ReadonlyArray < Statement > {
302
+ function transformCatch ( node : CallExpression , transformer : Transformer , prevArgName ?: SynthBindingName ) : ReadonlyArray < Statement > {
303
303
const func = node . arguments [ 0 ] ;
304
304
const argName = getArgBindingName ( func , transformer ) ;
305
305
const shouldReturn = transformer . setOfExpressionsToReturn . get ( getNodeId ( node ) . toString ( ) ) ;
306
+ let possibleNameForVarDecl : SynthIdentifier | undefined ;
306
307
307
308
/*
308
309
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)
309
310
To do this, we will need to synthesize a variable that we were not aware of while we were adding identifiers to the synthNamesMap
310
311
We will use the prevArgName and then update the synthNamesMap with a new variable name for the next transformation step
311
312
*/
312
313
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
+ }
320
330
331
+ possibleNameForVarDecl . numberOfAssignmentsOriginal = 2 ; // Try block and catch block
321
332
// 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 ) ;
324
335
}
325
336
}
326
337
327
- const tryBlock = createBlock ( transformExpression ( node . expression , transformer , node , prevArgName ) ) ;
338
+ const tryBlock = createBlock ( transformExpression ( node . expression , transformer , node , possibleNameForVarDecl ) ) ;
328
339
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" ;
331
342
const catchVariableDeclaration = createVariableDeclaration ( catchArg ) ;
332
343
const catchClause = createCatchClause ( catchVariableDeclaration , createBlock ( transformationBody ) ) ;
333
344
334
345
/*
335
346
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)
336
347
*/
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 ;
340
353
const unionType = transformer . checker . getUnionType ( typeArray , UnionReduction . Subtype ) ;
341
354
const unionTypeNode = transformer . isInJSFile ? undefined : transformer . checker . typeToTypeNode ( unionType ) ;
342
- const varDecl = [ createVariableDeclaration ( getSynthesizedDeepClone ( prevArgName . identifier ) , unionTypeNode ) ] ;
355
+ const varDecl = [ createVariableDeclaration ( varDeclIdentifier , unionTypeNode ) ] ;
343
356
varDeclList = createVariableStatement ( /*modifiers*/ undefined , createVariableDeclarationList ( varDecl , NodeFlags . Let ) ) ;
344
357
}
345
358
346
359
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 ] ) ;
348
363
}
349
364
350
365
function getIdentifierTextsFromBindingName ( bindingName : BindingName ) : ReadonlyArray < string > {
@@ -355,7 +370,7 @@ namespace ts.codefix {
355
370
} ) ;
356
371
}
357
372
358
- function createUniqueSynthName ( prevArgName : SynthIdentifier ) {
373
+ function createUniqueSynthName ( prevArgName : SynthIdentifier ) : SynthIdentifier {
359
374
const renamedPrevArg = createOptimisticUniqueName ( prevArgName . identifier . text ) ;
360
375
const newSynthName = { identifier : renamedPrevArg , types : [ ] , numberOfAssignmentsOriginal : 0 } ;
361
376
return newSynthName ;
@@ -378,7 +393,7 @@ namespace ts.codefix {
378
393
379
394
const transformationBody2 = getTransformationBody ( rej , prevArgName , argNameRej , node , transformer ) ;
380
395
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" ;
382
397
const catchVariableDeclaration = createVariableDeclaration ( catchArg ) ;
383
398
const catchClause = createCatchClause ( catchVariableDeclaration , createBlock ( transformationBody2 ) ) ;
384
399
@@ -414,7 +429,7 @@ namespace ts.codefix {
414
429
return [ createStatement ( rightHandSide ) ] ;
415
430
}
416
431
417
- if ( "identifier" in prevArgName && prevArgName . types . length < prevArgName . numberOfAssignmentsOriginal ) {
432
+ if ( isSynthIdentifier ( prevArgName ) && prevArgName . types . length < prevArgName . numberOfAssignmentsOriginal ) {
418
433
// if the variable has already been declared, we don't need "let" or "const"
419
434
return [ createStatement ( createAssignment ( getSynthesizedDeepClone ( prevArgName . identifier ) , rightHandSide ) ) ] ;
420
435
}
@@ -437,7 +452,7 @@ namespace ts.codefix {
437
452
break ;
438
453
}
439
454
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 ] : [ ] ) ;
441
456
if ( shouldReturn ) {
442
457
return [ createReturn ( synthCall ) ] ;
443
458
}
@@ -631,13 +646,21 @@ namespace ts.codefix {
631
646
if ( ! bindingName ) {
632
647
return true ;
633
648
}
634
- if ( "identifier" in bindingName ) {
649
+ if ( isSynthIdentifier ( bindingName ) ) {
635
650
return ! bindingName . identifier . text ;
636
651
}
637
652
return every ( bindingName . elements , isEmpty ) ;
638
653
}
639
654
640
655
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 ;
642
665
}
643
666
}
0 commit comments