diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 1845f2b601..02e20b0fb7 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -4748,7 +4748,6 @@
"category": "Message",
"code": 95062
},
-
"Add missing enum member '{0}'": {
"category": "Message",
"code": 95063
@@ -4780,5 +4779,13 @@
"Add 'unknown' to all conversions of non-overlapping types": {
"category": "Message",
"code": 95070
+ },
+ "Add missing 'new' operator to call": {
+ "category": "Message",
+ "code": 95071
+ },
+ "Add missing 'new' operator to all calls": {
+ "category": "Message",
+ "code": 95072
}
}
diff --git a/src/services/codefixes/fixAddMissingNewOperator.ts b/src/services/codefixes/fixAddMissingNewOperator.ts
new file mode 100644
index 0000000000..5acaf6eb82
--- /dev/null
+++ b/src/services/codefixes/fixAddMissingNewOperator.ts
@@ -0,0 +1,32 @@
+/* @internal */
+namespace ts.codefix {
+ const fixId = "addMissingNewOperator";
+ const errorCodes = [Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new.code];
+ registerCodeFix({
+ errorCodes,
+ getCodeActions(context) {
+ const { sourceFile, span } = context;
+ const changes = textChanges.ChangeTracker.with(context, t => addMissingNewOperator(t, sourceFile, span));
+ return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_new_operator_to_call, fixId, Diagnostics.Add_missing_new_operator_to_all_calls)];
+ },
+ fixIds: [fixId],
+ getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) =>
+ addMissingNewOperator(changes, context.sourceFile, diag)),
+ });
+
+ function addMissingNewOperator(changes: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan): void {
+ const call = cast(findAncestorMatchingSpan(sourceFile, span), isCallExpression);
+ const newExpression = createNew(call.expression, call.typeArguments, call.arguments);
+
+ changes.replaceNode(sourceFile, call, newExpression);
+ }
+
+ function findAncestorMatchingSpan(sourceFile: SourceFile, span: TextSpan): Node {
+ let token = getTokenAtPosition(sourceFile, span.start);
+ const end = textSpanEnd(span);
+ while (token.end < end) {
+ token = token.parent;
+ }
+ return token;
+ }
+}
diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json
index 4c2147cf38..f59d273d7b 100644
--- a/src/services/tsconfig.json
+++ b/src/services/tsconfig.json
@@ -55,6 +55,7 @@
"codefixes/importFixes.ts",
"codefixes/fixSpelling.ts",
"codefixes/fixAddMissingMember.ts",
+ "codefixes/fixAddMissingNewOperator.ts",
"codefixes/fixCannotFindModule.ts",
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
diff --git a/tests/cases/fourslash/codeFixAddMissingNew.ts b/tests/cases/fourslash/codeFixAddMissingNew.ts
new file mode 100644
index 0000000000..ff1ce125c9
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew.ts
@@ -0,0 +1,14 @@
+///
+
+////class C {
+////}
+////var c = C();
+
+verify.codeFix({
+ description: "Add missing 'new' operator to call",
+ index: 0,
+ newFileContent:
+`class C {
+}
+var c = new C();`
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingNew2.ts b/tests/cases/fourslash/codeFixAddMissingNew2.ts
new file mode 100644
index 0000000000..a90b1c580d
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew2.ts
@@ -0,0 +1,14 @@
+///
+
+////class C {
+////}
+////let x = (() => C)()();
+
+verify.codeFix({
+ description: "Add missing 'new' operator to call",
+ index: 0,
+ newFileContent:
+`class C {
+}
+let x = new ((() => C)())();`
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingNew3.ts b/tests/cases/fourslash/codeFixAddMissingNew3.ts
new file mode 100644
index 0000000000..c420d0446b
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew3.ts
@@ -0,0 +1,16 @@
+///
+
+////class C {
+////}
+////let x = [C];
+////let a = x[0]();
+
+verify.codeFix({
+ description: "Add missing 'new' operator to call",
+ index: 0,
+ newFileContent:
+`class C {
+}
+let x = [C];
+let a = new x[0]();`
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingNew4.ts b/tests/cases/fourslash/codeFixAddMissingNew4.ts
new file mode 100644
index 0000000000..e216b28bf5
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew4.ts
@@ -0,0 +1,18 @@
+///
+
+////class C {
+////}
+////class D {
+////}
+////let x = (true ? C : D)();
+
+verify.codeFix({
+ description: "Add missing 'new' operator to call",
+ index: 0,
+ newFileContent:
+`class C {
+}
+class D {
+}
+let x = new (true ? C : D)();`
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingNew5.ts b/tests/cases/fourslash/codeFixAddMissingNew5.ts
new file mode 100644
index 0000000000..ecc5509a18
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew5.ts
@@ -0,0 +1,25 @@
+///
+
+////class C {
+////}
+////
+////function foo() {
+//// return C;
+////}
+////
+////foo()!();
+
+
+verify.codeFix({
+ description: "Add missing 'new' operator to call",
+ index: 0,
+ newFileContent:
+`class C {
+}
+
+function foo() {
+ return C;
+}
+
+new (foo()!)();`
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingNew_all.ts b/tests/cases/fourslash/codeFixAddMissingNew_all.ts
new file mode 100644
index 0000000000..019f5b5a5a
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew_all.ts
@@ -0,0 +1,18 @@
+///
+
+////class C {
+//// constructor(num?: number) {}
+////}
+////var a = C();
+////var b = C(3);
+
+verify.codeFixAll({
+ fixId: "addMissingNewOperator",
+ fixAllDescription: "Add missing 'new' operator to all calls",
+ newFileContent:
+`class C {
+ constructor(num?: number) {}
+}
+var a = new C();
+var b = new C(3);`
+});
diff --git a/tests/cases/fourslash/codeFixAddMissingNew_all_arguments.ts b/tests/cases/fourslash/codeFixAddMissingNew_all_arguments.ts
new file mode 100644
index 0000000000..130dfd28fd
--- /dev/null
+++ b/tests/cases/fourslash/codeFixAddMissingNew_all_arguments.ts
@@ -0,0 +1,22 @@
+///
+
+////class C {
+//// x?: T;
+//// constructor(x: T) { this.x = x; }
+////}
+////let a = C(1, 2, 3);
+////let b = C("hello");
+////let c = C();
+
+verify.codeFixAll({
+ fixId: "addMissingNewOperator",
+ fixAllDescription: "Add missing 'new' operator to all calls",
+ newFileContent:
+`class C {
+ x?: T;
+ constructor(x: T) { this.x = x; }
+}
+let a = new C(1, 2, 3);
+let b = new C("hello");
+let c = new C();`
+});