diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index aa0091f99523a..6a667916b38d2 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -23889,7 +23889,10 @@ namespace ts {
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
isObjectLiteralMethod(memberDecl)) {
let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) :
- memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(memberDecl.name, checkMode) :
+ // avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring
+ // for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`.
+ // we don't want to say "could not find 'a'".
+ memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) :
checkObjectLiteralMethod(memberDecl, checkMode);
if (isInJavascript) {
const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl);
@@ -38218,7 +38221,7 @@ namespace ts {
if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && prop.objectAssignmentInitializer) {
// having objectAssignmentInitializer is only valid in ObjectAssignmentPattern
// outside of destructuring it is a syntax error
- return grammarErrorOnNode(prop.equalsToken!, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment);
+ return grammarErrorOnNode(prop.equalsToken!, Diagnostics.Did_you_mean_to_use_a_Colon_When_following_property_names_in_an_object_literal_implies_a_destructuring_assignment);
}
if (name.kind === SyntaxKind.PrivateIdentifier) {
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index b32e8d020290b..dc21a3581324a 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -880,7 +880,7 @@
"category": "Error",
"code": 1308
},
- "'=' can only be used in an object literal property inside a destructuring assignment.": {
+ "Did you mean to use a ':'? When following property names in an object literal, '=' implies a destructuring assignment.": {
"category": "Error",
"code": 1312
},
@@ -5819,6 +5819,10 @@
"category": "Message",
"code": 95137
},
+ "Switch each misused '{0}' to '{1}'": {
+ "category": "Message",
+ "code": 95138
+ },
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",
diff --git a/src/services/codefixes/fixPropertyAssignment.ts b/src/services/codefixes/fixPropertyAssignment.ts
new file mode 100644
index 0000000000000..ee46d90858b83
--- /dev/null
+++ b/src/services/codefixes/fixPropertyAssignment.ts
@@ -0,0 +1,28 @@
+/* @internal */
+namespace ts.codefix {
+ const fixId = "fixPropertyAssignment";
+ const errorCodes = [
+ Diagnostics.Did_you_mean_to_use_a_Colon_When_following_property_names_in_an_object_literal_implies_a_destructuring_assignment.code
+ ];
+
+ registerCodeFix({
+ errorCodes,
+ fixIds: [fixId],
+ getCodeActions(context) {
+ const { sourceFile, span } = context;
+ const property = getProperty(sourceFile, span.start);
+ const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, property));
+ return [createCodeFixAction(fixId, changes, [Diagnostics.Change_0_to_1, "=", ":"], fixId, [Diagnostics.Switch_each_misused_0_to_1, "=", ":"])];
+ },
+ getAllCodeActions: context =>
+ codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, getProperty(diag.file, diag.start)))
+ });
+
+ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: ShorthandPropertyAssignment): void {
+ changes.replaceNode(sourceFile, node, factory.createPropertyAssignment(node.name, node.objectAssignmentInitializer as Expression));
+ }
+
+ function getProperty(sourceFile: SourceFile, pos: number): ShorthandPropertyAssignment {
+ return cast(getTokenAtPosition(sourceFile, pos).parent, isShorthandPropertyAssignment);
+ }
+}
diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json
index 9567185c7a9ac..e1aab52f187f1 100644
--- a/src/services/tsconfig.json
+++ b/src/services/tsconfig.json
@@ -76,6 +76,7 @@
"codefixes/fixEnableExperimentalDecorators.ts",
"codefixes/fixEnableJsxFlag.ts",
"codefixes/fixModuleAndTargetOptions.ts",
+ "codefixes/fixPropertyAssignment.ts",
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
"codefixes/fixForgottenThisPropertyAccess.ts",
"codefixes/fixInvalidJsxCharacters.ts",
diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt
index cb22c03a20b60..ba8af08a9cbf3 100644
--- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt
+++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt
@@ -11,11 +11,10 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(85,19): erro
Types of property 'x' are incompatible.
Type 'number' is not assignable to type 'string'.
tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(85,26): error TS2322: Type 'number' is not assignable to type 'string'.
-tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(111,12): error TS18004: No value exists in scope for the shorthand property 's'. Either declare one or provide an initializer.
-tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(111,14): error TS1312: '=' can only be used in an object literal property inside a destructuring assignment.
+tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(111,14): error TS1312: Did you mean to use a ':'? When following property names in an object literal, '=' implies a destructuring assignment.
-==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts (13 errors) ====
+==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts (12 errors) ====
(function() {
var s0;
for ({ s0 = 5 } of [{ s0: 1 }]) {
@@ -153,10 +152,8 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(111,14): err
(function() {
let a = { s = 5 };
- ~
-!!! error TS18004: No value exists in scope for the shorthand property 's'. Either declare one or provide an initializer.
~
-!!! error TS1312: '=' can only be used in an object literal property inside a destructuring assignment.
+!!! error TS1312: Did you mean to use a ':'? When following property names in an object literal, '=' implies a destructuring assignment.
});
function foo({a = 4, b = { x: 5 }}) {
diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.types b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.types
index b160cd31b1290..9e44644904c41 100644
--- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.types
+++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.types
@@ -417,8 +417,8 @@
>function() { let a = { s = 5 };} : () => void
let a = { s = 5 };
->a : { s: any; }
->{ s = 5 } : { s: any; }
+>a : { s: number; }
+>{ s = 5 } : { s: number; }
>s : any
>5 : 5
diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt
index fb368df29c380..d6b0da61711cb 100644
--- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt
+++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt
@@ -11,11 +11,10 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(85,19):
Types of property 'x' are incompatible.
Type 'number' is not assignable to type 'string'.
tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(85,26): error TS2322: Type 'number' is not assignable to type 'string'.
-tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(111,12): error TS18004: No value exists in scope for the shorthand property 's'. Either declare one or provide an initializer.
-tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(111,14): error TS1312: '=' can only be used in an object literal property inside a destructuring assignment.
+tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(111,14): error TS1312: Did you mean to use a ':'? When following property names in an object literal, '=' implies a destructuring assignment.
-==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts (13 errors) ====
+==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts (12 errors) ====
(function() {
var s0;
for ({ s0 = 5 } of [{ s0: 1 }]) {
@@ -153,10 +152,8 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(111,14):
(function() {
let a = { s = 5 };
- ~
-!!! error TS18004: No value exists in scope for the shorthand property 's'. Either declare one or provide an initializer.
~
-!!! error TS1312: '=' can only be used in an object literal property inside a destructuring assignment.
+!!! error TS1312: Did you mean to use a ':'? When following property names in an object literal, '=' implies a destructuring assignment.
});
function foo({a = 4, b = { x: 5 }}) {
diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.types b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.types
index 1cdc84e83ba71..68ff6a0a26a7f 100644
--- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.types
+++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.types
@@ -417,8 +417,8 @@
>function() { let a = { s = 5 };} : () => void
let a = { s = 5 };
->a : { s: any; }
->{ s = 5 } : { s: any; }
+>a : { s: number; }
+>{ s = 5 } : { s: number; }
>s : any
>5 : 5
diff --git a/tests/cases/fourslash/codeFixPropertyAssignment1.ts b/tests/cases/fourslash/codeFixPropertyAssignment1.ts
new file mode 100644
index 0000000000000..3745a91f7540a
--- /dev/null
+++ b/tests/cases/fourslash/codeFixPropertyAssignment1.ts
@@ -0,0 +1,14 @@
+///
+
+////const a = {
+//// x/**/= 1
+////}
+
+verify.codeFix({
+ description: [ts.Diagnostics.Change_0_to_1.message, "=", ":"],
+ index: 0,
+ newFileContent:
+`const a = {
+ x: 1
+}`,
+});
diff --git a/tests/cases/fourslash/codeFixPropertyAssignment2.ts b/tests/cases/fourslash/codeFixPropertyAssignment2.ts
new file mode 100644
index 0000000000000..233e612a9a054
--- /dev/null
+++ b/tests/cases/fourslash/codeFixPropertyAssignment2.ts
@@ -0,0 +1,14 @@
+///
+
+////const a = {
+//// x /**/= 1
+////}
+
+verify.codeFix({
+ description: [ts.Diagnostics.Change_0_to_1.message, "=", ":"],
+ index: 0,
+ newFileContent:
+`const a = {
+ x: 1
+}`,
+});
diff --git a/tests/cases/fourslash/codeFixPropertyAssignment3.ts b/tests/cases/fourslash/codeFixPropertyAssignment3.ts
new file mode 100644
index 0000000000000..8346230588e22
--- /dev/null
+++ b/tests/cases/fourslash/codeFixPropertyAssignment3.ts
@@ -0,0 +1,18 @@
+///
+
+////const a = {
+//// x: 1,
+//// y /**/= 1,
+//// z: 1
+////}
+
+verify.codeFix({
+ description: [ts.Diagnostics.Change_0_to_1.message, "=", ":"],
+ index: 0,
+ newFileContent:
+`const a = {
+ x: 1,
+ y: 1,
+ z: 1
+}`,
+});
diff --git a/tests/cases/fourslash/codeFixPropertyAssignment_fixAll.ts b/tests/cases/fourslash/codeFixPropertyAssignment_fixAll.ts
new file mode 100644
index 0000000000000..5cf54db26b1be
--- /dev/null
+++ b/tests/cases/fourslash/codeFixPropertyAssignment_fixAll.ts
@@ -0,0 +1,34 @@
+///
+
+////const a = {
+//// x: 1,
+//// y = 1,
+//// z: 1
+////}
+////const b = {
+//// x = 1,
+//// y: 1
+////}
+////const c = {
+//// x: 1,
+//// y = 1
+////}
+
+verify.codeFixAll({
+ fixAllDescription: "Switch each misused '=' to ':'",
+ fixId: "fixPropertyAssignment",
+ newFileContent:
+`const a = {
+ x: 1,
+ y: 1,
+ z: 1
+}
+const b = {
+ x: 1,
+ y: 1
+}
+const c = {
+ x: 1,
+ y: 1
+}`
+});