From da5f0fe9d4f273d0fb67039c67c7edc3a69ea3a9 Mon Sep 17 00:00:00 2001
From: hborchardt <66408901+hborchardt@users.noreply.github.com>
Date: Thu, 15 Feb 2024 20:49:38 +0100
Subject: [PATCH] Add missing members to array of objects in quickfix (#57143)
---
src/services/codefixes/fixAddMissingMember.ts | 20 ++++++++++++++----
.../codeFixAddMissingProperties30.ts | 21 +++++++++++++++++++
.../codeFixAddMissingProperties31.ts | 21 +++++++++++++++++++
3 files changed, 58 insertions(+), 4 deletions(-)
create mode 100644 tests/cases/fourslash/codeFixAddMissingProperties30.ts
create mode 100644 tests/cases/fourslash/codeFixAddMissingProperties31.ts
diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts
index 9ef55283fd6..1210275178f 100644
--- a/src/services/codefixes/fixAddMissingMember.ts
+++ b/src/services/codefixes/fixAddMissingMember.ts
@@ -187,7 +187,7 @@ registerCodeFix({
return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => {
eachDiagnostic(context, errorCodes, diag => {
const info = getInfo(diag.file, diag.start, diag.code, checker, context.program);
- if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + info.token.text)) {
+ if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + (info.kind === InfoKind.ObjectLiteral ? info.identifier : info.token.text))) {
return;
}
if (fixId === fixMissingFunctionDeclaration && (info.kind === InfoKind.Function || info.kind === InfoKind.Signature)) {
@@ -273,7 +273,8 @@ interface FunctionInfo {
interface ObjectLiteralInfo {
readonly kind: InfoKind.ObjectLiteral;
- readonly token: Identifier;
+ readonly token: Node;
+ readonly identifier: string;
readonly properties: Symbol[];
readonly parentDeclaration: ObjectLiteralExpression;
readonly indentation?: number;
@@ -315,7 +316,18 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch
const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), checker.getParameterType(signature, argIndex), /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false));
if (!length(properties)) return undefined;
- return { kind: InfoKind.ObjectLiteral, token: param.name, properties, parentDeclaration: parent };
+ return { kind: InfoKind.ObjectLiteral, token: param.name, identifier: param.name.text, properties, parentDeclaration: parent };
+ }
+
+ if (token.kind === SyntaxKind.OpenBraceToken && isObjectLiteralExpression(parent)) {
+ const targetType = checker.getContextualType(parent) || checker.getTypeAtLocation(parent);
+ const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), targetType, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false));
+ if (!length(properties)) return undefined;
+
+ // no identifier needed because the whole parentDeclaration has the error
+ const identifier = "";
+
+ return { kind: InfoKind.ObjectLiteral, token: parent, identifier, properties, parentDeclaration: parent };
}
if (!isMemberName(token)) return undefined;
@@ -325,7 +337,7 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch
const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent.initializer), targetType, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false));
if (!length(properties)) return undefined;
- return { kind: InfoKind.ObjectLiteral, token, properties, parentDeclaration: parent.initializer };
+ return { kind: InfoKind.ObjectLiteral, token, identifier: token.text, properties, parentDeclaration: parent.initializer };
}
if (isIdentifier(token) && isJsxOpeningLikeElement(token.parent)) {
diff --git a/tests/cases/fourslash/codeFixAddMissingProperties30.ts b/tests/cases/fourslash/codeFixAddMissingProperties30.ts
new file mode 100644
index 00000000000..3475c38db76
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingProperties30.ts
@@ -0,0 +1,21 @@
+///
+
+////interface A {
+//// a: number;
+//// b: string;
+////}
+////function f(_obj: A[]): string {
+//// return "";
+////}
+////[|f([{}])|]
+
+debugger;
+verify.codeFix({
+ index: 0,
+ description: ts.Diagnostics.Add_missing_properties.message,
+ newRangeContent:
+`f([{
+ a: 0,
+ b: ""
+}])`,
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingProperties31.ts b/tests/cases/fourslash/codeFixAddMissingProperties31.ts
new file mode 100644
index 00000000000..c05e87d68d4
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingProperties31.ts
@@ -0,0 +1,21 @@
+///
+
+////interface A {
+//// a: number;
+//// b: string;
+////}
+////interface B {
+//// c: A[];
+////}
+////[|const b: B[] = [{c: [{}]}]|]
+
+debugger;
+verify.codeFix({
+ index: 0,
+ description: ts.Diagnostics.Add_missing_properties.message,
+ newRangeContent:
+`const b: B[] = [{c: [{
+ a: 0,
+ b: ""
+}]}]`,
+});