@@ -1015,6 +1015,7 @@ namespace ts {
1015
1015
const potentialNewTargetCollisions: Node[] = [];
1016
1016
const potentialWeakMapSetCollisions: Node[] = [];
1017
1017
const potentialReflectCollisions: Node[] = [];
1018
+ const potentialUnusedRenamedBindingElementsInTypes: BindingElement[] = [];
1018
1019
const awaitedTypeStack: number[] = [];
1019
1020
1020
1021
const diagnostics = createDiagnosticCollection();
@@ -5945,19 +5946,29 @@ namespace ts {
5945
5946
return parameterNode;
5946
5947
5947
5948
function cloneBindingName(node: BindingName): BindingName {
5948
- return elideInitializerAndSetEmitFlags (node) as BindingName;
5949
- function elideInitializerAndSetEmitFlags (node: Node): Node {
5949
+ return elideInitializerAndPropertyRenamingAndSetEmitFlags (node) as BindingName;
5950
+ function elideInitializerAndPropertyRenamingAndSetEmitFlags (node: Node): Node {
5950
5951
if (context.tracker.trackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) {
5951
5952
trackComputedName(node.expression, context.enclosingDeclaration, context);
5952
5953
}
5953
- let visited = visitEachChild(node, elideInitializerAndSetEmitFlags , nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags )!;
5954
+ let visited = visitEachChild(node, elideInitializerAndPropertyRenamingAndSetEmitFlags , nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndPropertyRenamingAndSetEmitFlags )!;
5954
5955
if (isBindingElement(visited)) {
5955
- visited = factory.updateBindingElement(
5956
- visited,
5957
- visited.dotDotDotToken,
5958
- visited.propertyName,
5959
- visited.name,
5960
- /*initializer*/ undefined);
5956
+ if (visited.propertyName && isIdentifier(visited.propertyName) && isIdentifier(visited.name)) {
5957
+ visited = factory.updateBindingElement(
5958
+ visited,
5959
+ visited.dotDotDotToken,
5960
+ /* propertyName*/ undefined,
5961
+ visited.propertyName,
5962
+ /*initializer*/ undefined);
5963
+ }
5964
+ else {
5965
+ visited = factory.updateBindingElement(
5966
+ visited,
5967
+ visited.dotDotDotToken,
5968
+ visited.propertyName,
5969
+ visited.name,
5970
+ /*initializer*/ undefined);
5971
+ }
5961
5972
}
5962
5973
if (!nodeIsSynthesized(visited)) {
5963
5974
visited = factory.cloneNode(visited);
@@ -37432,6 +37443,24 @@ namespace ts {
37432
37443
});
37433
37444
}
37434
37445
37446
+ function checkPotentialUncheckedRenamedBindingElementsInTypes() {
37447
+ for (const node of potentialUnusedRenamedBindingElementsInTypes) {
37448
+ if (!getSymbolOfNode(node)?.isReferenced) {
37449
+ const wrappingDeclaration = walkUpBindingElementsAndPatterns(node);
37450
+ Debug.assert(isParameterDeclaration(wrappingDeclaration), "Only parameter declaration should be checked here");
37451
+ const diagnostic = createDiagnosticForNode(node.name, Diagnostics._0_is_an_unused_renaming_of_1_Did_you_intend_to_use_it_as_a_type_annotation, declarationNameToString(node.name), declarationNameToString(node.propertyName));
37452
+ if (!wrappingDeclaration.type) {
37453
+ // entire parameter does not have type annotation, suggest adding an annotation
37454
+ addRelatedInfo(
37455
+ diagnostic,
37456
+ createFileDiagnostic(getSourceFileOfNode(wrappingDeclaration), wrappingDeclaration.end, 1, Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, declarationNameToString(node.propertyName))
37457
+ );
37458
+ }
37459
+ diagnostics.add(diagnostic);
37460
+ }
37461
+ }
37462
+ }
37463
+
37435
37464
function bindingNameText(name: BindingName): string {
37436
37465
switch (name.kind) {
37437
37466
case SyntaxKind.Identifier:
@@ -37773,6 +37802,19 @@ namespace ts {
37773
37802
}
37774
37803
37775
37804
if (isBindingElement(node)) {
37805
+ if (
37806
+ node.propertyName &&
37807
+ isIdentifier(node.name) &&
37808
+ isParameterDeclaration(node) &&
37809
+ nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) {
37810
+ // type F = ({a: string}) => void;
37811
+ // ^^^^^^
37812
+ // variable renaming in function type notation is confusing,
37813
+ // so we forbid it even if noUnusedLocals is not enabled
37814
+ potentialUnusedRenamedBindingElementsInTypes.push(node);
37815
+ return;
37816
+ }
37817
+
37776
37818
if (isObjectBindingPattern(node.parent) && node.dotDotDotToken && languageVersion < ScriptTarget.ES2018) {
37777
37819
checkExternalEmitHelpers(node, ExternalEmitHelpers.Rest);
37778
37820
}
@@ -41617,6 +41659,7 @@ namespace ts {
41617
41659
clear(potentialNewTargetCollisions);
41618
41660
clear(potentialWeakMapSetCollisions);
41619
41661
clear(potentialReflectCollisions);
41662
+ clear(potentialUnusedRenamedBindingElementsInTypes);
41620
41663
41621
41664
forEach(node.statements, checkSourceElement);
41622
41665
checkSourceElement(node.endOfFileToken);
@@ -41636,6 +41679,9 @@ namespace ts {
41636
41679
}
41637
41680
});
41638
41681
}
41682
+ if (!node.isDeclarationFile) {
41683
+ checkPotentialUncheckedRenamedBindingElementsInTypes();
41684
+ }
41639
41685
});
41640
41686
41641
41687
if (compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error &&
0 commit comments