@@ -81,7 +81,7 @@ namespace ts.refactor.convertParamsToDestructuredObject {
81
81
const references = flatMap ( names , /*mapfn*/ name => FindAllReferences . getReferenceEntriesForNode ( - 1 , name , program , program . getSourceFiles ( ) , cancellationToken ) ) ;
82
82
const groupedReferences = groupReferences ( references ) ;
83
83
84
- if ( ! every ( groupedReferences . declarations , decl => contains ( names , decl ) ) ) {
84
+ if ( ! every ( groupedReferences . declarations , /*callback*/ decl => contains ( names , decl ) ) ) {
85
85
groupedReferences . valid = false ;
86
86
}
87
87
@@ -241,18 +241,26 @@ namespace ts.refactor.convertParamsToDestructuredObject {
241
241
return undefined ;
242
242
}
243
243
244
- function isValidFunctionDeclaration ( functionDeclaration : SignatureDeclaration , checker : TypeChecker ) : functionDeclaration is ValidFunctionDeclaration {
245
- if ( ! isValidParameterNodeArray ( functionDeclaration . parameters ) ) return false ;
244
+ function isValidFunctionDeclaration (
245
+ functionDeclaration : SignatureDeclaration ,
246
+ checker : TypeChecker ) : functionDeclaration is ValidFunctionDeclaration {
247
+ if ( ! isValidParameterNodeArray ( functionDeclaration . parameters , checker ) ) return false ;
246
248
switch ( functionDeclaration . kind ) {
247
249
case SyntaxKind . FunctionDeclaration :
248
250
case SyntaxKind . MethodDeclaration :
249
- return ! ! functionDeclaration . name && ! ! functionDeclaration . body && ! checker . isImplementationOfOverload ( functionDeclaration ) ;
251
+ return ! ! functionDeclaration . name
252
+ && ! ! functionDeclaration . body
253
+ && ! checker . isImplementationOfOverload ( functionDeclaration ) ;
250
254
case SyntaxKind . Constructor :
251
255
if ( isClassDeclaration ( functionDeclaration . parent ) ) {
252
- return ! ! functionDeclaration . body && ! ! functionDeclaration . parent . name && ! checker . isImplementationOfOverload ( functionDeclaration ) ;
256
+ return ! ! functionDeclaration . body
257
+ && ! ! functionDeclaration . parent . name
258
+ && ! checker . isImplementationOfOverload ( functionDeclaration ) ;
253
259
}
254
260
else {
255
- return isValidVariableDeclaration ( functionDeclaration . parent . parent ) && ! ! functionDeclaration . body && ! checker . isImplementationOfOverload ( functionDeclaration ) ;
261
+ return isValidVariableDeclaration ( functionDeclaration . parent . parent )
262
+ && ! ! functionDeclaration . body
263
+ && ! checker . isImplementationOfOverload ( functionDeclaration ) ;
256
264
}
257
265
case SyntaxKind . FunctionExpression :
258
266
case SyntaxKind . ArrowFunction :
@@ -261,12 +269,21 @@ namespace ts.refactor.convertParamsToDestructuredObject {
261
269
return false ;
262
270
}
263
271
264
- function isValidParameterNodeArray ( parameters : NodeArray < ParameterDeclaration > ) : parameters is ValidParameterNodeArray {
265
- return getRefactorableParametersLength ( parameters ) >= minimumParameterLength && every ( parameters , isValidParameterDeclaration ) ;
272
+ function isValidParameterNodeArray (
273
+ parameters : NodeArray < ParameterDeclaration > ,
274
+ checker : TypeChecker ) : parameters is ValidParameterNodeArray {
275
+ return getRefactorableParametersLength ( parameters ) >= minimumParameterLength
276
+ && every ( parameters , /*callback*/ paramDecl => isValidParameterDeclaration ( paramDecl , checker ) ) ;
266
277
}
267
278
268
- function isValidParameterDeclaration ( paramDeclaration : ParameterDeclaration ) : paramDeclaration is ValidParameterDeclaration {
269
- return ! paramDeclaration . modifiers && ! paramDeclaration . decorators && isIdentifier ( paramDeclaration . name ) ;
279
+ function isValidParameterDeclaration (
280
+ parameterDeclaration : ParameterDeclaration ,
281
+ checker : TypeChecker ) : parameterDeclaration is ValidParameterDeclaration {
282
+ if ( isRestParameter ( parameterDeclaration ) ) {
283
+ const type = checker . getTypeAtLocation ( parameterDeclaration ) ;
284
+ if ( ! checker . isArrayType ( type ) && ! checker . isTupleType ( type ) ) return false ;
285
+ }
286
+ return ! parameterDeclaration . modifiers && ! parameterDeclaration . decorators && isIdentifier ( parameterDeclaration . name ) ;
270
287
}
271
288
272
289
function isValidVariableDeclaration ( node : Node ) : node is ValidVariableDeclaration {
@@ -313,15 +330,15 @@ namespace ts.refactor.convertParamsToDestructuredObject {
313
330
}
314
331
315
332
function createNewParameters ( functionDeclaration : ValidFunctionDeclaration , program : Program , host : LanguageServiceHost ) : NodeArray < ParameterDeclaration > {
333
+ const checker = program . getTypeChecker ( ) ;
316
334
const refactorableParameters = getRefactorableParameters ( functionDeclaration . parameters ) ;
317
335
const bindingElements = map ( refactorableParameters , createBindingElementFromParameterDeclaration ) ;
318
336
const objectParameterName = createObjectBindingPattern ( bindingElements ) ;
319
337
const objectParameterType = createParameterTypeNode ( refactorableParameters ) ;
320
- const checker = program . getTypeChecker ( ) ;
321
338
322
339
let objectInitializer : Expression | undefined ;
323
340
// If every parameter in the original function was optional, add an empty object initializer to the new object parameter
324
- if ( every ( refactorableParameters , checker . isOptionalParameter ) ) {
341
+ if ( every ( refactorableParameters , isOptionalParameter ) ) {
325
342
objectInitializer = createObjectLiteral ( ) ;
326
343
}
327
344
@@ -355,6 +372,20 @@ namespace ts.refactor.convertParamsToDestructuredObject {
355
372
}
356
373
return createNodeArray ( [ objectParameter ] ) ;
357
374
375
+ function createBindingElementFromParameterDeclaration ( parameterDeclaration : ValidParameterDeclaration ) : BindingElement {
376
+ const element = createBindingElement (
377
+ /*dotDotDotToken*/ undefined ,
378
+ /*propertyName*/ undefined ,
379
+ getParameterName ( parameterDeclaration ) ,
380
+ isRestParameter ( parameterDeclaration ) && isOptionalParameter ( parameterDeclaration ) ? createArrayLiteral ( ) : parameterDeclaration . initializer ) ;
381
+
382
+ suppressLeadingAndTrailingTrivia ( element ) ;
383
+ if ( parameterDeclaration . initializer && element . initializer ) {
384
+ copyComments ( parameterDeclaration . initializer , element . initializer ) ;
385
+ }
386
+ return element ;
387
+ }
388
+
358
389
function createParameterTypeNode ( parameters : NodeArray < ValidParameterDeclaration > ) : TypeLiteralNode {
359
390
const members = map ( parameters , createPropertySignatureFromParameterDeclaration ) ;
360
391
const typeNode = addEmitFlags ( createTypeLiteralNode ( members ) , EmitFlags . SingleLine ) ;
@@ -370,7 +401,7 @@ namespace ts.refactor.convertParamsToDestructuredObject {
370
401
const propertySignature = createPropertySignature (
371
402
/*modifiers*/ undefined ,
372
403
getParameterName ( parameterDeclaration ) ,
373
- parameterDeclaration . initializer || isRestParameter ( parameterDeclaration ) ? createToken ( SyntaxKind . QuestionToken ) : parameterDeclaration . questionToken ,
404
+ isOptionalParameter ( parameterDeclaration ) ? createToken ( SyntaxKind . QuestionToken ) : parameterDeclaration . questionToken ,
374
405
parameterType ,
375
406
/*initializer*/ undefined ) ;
376
407
@@ -384,24 +415,17 @@ namespace ts.refactor.convertParamsToDestructuredObject {
384
415
}
385
416
386
417
function getTypeNode ( node : Node ) : TypeNode | undefined {
387
- const checker = program . getTypeChecker ( ) ;
388
418
const type = checker . getTypeAtLocation ( node ) ;
389
419
return getTypeNodeIfAccessible ( type , node , program , host ) ;
390
420
}
391
- }
392
421
393
- function createBindingElementFromParameterDeclaration ( parameterDeclaration : ValidParameterDeclaration ) : BindingElement {
394
- const element = createBindingElement (
395
- /*dotDotDotToken*/ undefined ,
396
- /*propertyName*/ undefined ,
397
- getParameterName ( parameterDeclaration ) ,
398
- isRestParameter ( parameterDeclaration ) ? createArrayLiteral ( ) : parameterDeclaration . initializer ) ;
399
-
400
- suppressLeadingAndTrailingTrivia ( element ) ;
401
- if ( parameterDeclaration . initializer && element . initializer ) {
402
- copyComments ( parameterDeclaration . initializer , element . initializer ) ;
422
+ function isOptionalParameter ( parameterDeclaration : ValidParameterDeclaration ) : boolean {
423
+ if ( isRestParameter ( parameterDeclaration ) ) {
424
+ const type = checker . getTypeAtLocation ( parameterDeclaration ) ;
425
+ return ! checker . isTupleType ( type ) ;
426
+ }
427
+ return checker . isOptionalParameter ( parameterDeclaration ) ;
403
428
}
404
- return element ;
405
429
}
406
430
407
431
function copyComments ( sourceNode : Node , targetNode : Node ) {
0 commit comments