diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 0d9e7a0a6bf09..1ffc78134c318 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -3657,6 +3657,10 @@
"category": "Message",
"code": 90025
},
+ "Rewrite as the indexed access type '{0}'.": {
+ "category": "Message",
+ "code": 90026
+ },
"Convert function to an ES2015 class": {
"category": "Message",
diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json
index 8d52791f539a5..66ca2fc3f4837 100644
--- a/src/harness/tsconfig.json
+++ b/src/harness/tsconfig.json
@@ -74,11 +74,6 @@
"../services/formatting/tokenRange.ts",
"../services/codeFixProvider.ts",
"../services/codefixes/fixes.ts",
- "../services/codefixes/fixExtendsInterfaceBecomesImplements.ts",
- "../services/codefixes/fixClassIncorrectlyImplementsInterface.ts",
- "../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
- "../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts",
- "../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"../services/codefixes/helpers.ts",
"../services/codefixes/importFixes.ts",
"../services/codefixes/fixUnusedIdentifier.ts",
diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts
new file mode 100644
index 0000000000000..3087d73276dec
--- /dev/null
+++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts
@@ -0,0 +1,27 @@
+/* @internal */
+namespace ts.codefix {
+ registerCodeFix({
+ errorCodes: [Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1.code],
+ getCodeActions: (context: CodeFixContext) => {
+ const sourceFile = context.sourceFile;
+ const token = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false);
+ const qualifiedName = getAncestor(token, SyntaxKind.QualifiedName) as QualifiedName;
+ Debug.assert(!!qualifiedName, "Expected position to be owned by a qualified name.");
+ if (!isIdentifier(qualifiedName.left)) {
+ return undefined;
+ }
+ const leftText = qualifiedName.left.getText(sourceFile);
+ const rightText = qualifiedName.right.getText(sourceFile);
+ const replacement = createIndexedAccessTypeNode(
+ createTypeReferenceNode(qualifiedName.left, /*typeArguments*/ undefined),
+ createLiteralTypeNode(createLiteral(rightText)));
+ const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
+ changeTracker.replaceNode(sourceFile, qualifiedName, replacement);
+
+ return [{
+ description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Rewrite_as_the_indexed_access_type_0), [`${leftText}["${rightText}"]`]),
+ changes: changeTracker.getChanges()
+ }];
+ }
+ });
+}
diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts
index ef670c81ba9d6..9bc80cad69117 100644
--- a/src/services/codefixes/fixes.ts
+++ b/src/services/codefixes/fixes.ts
@@ -1,3 +1,4 @@
+///
///
///
///
diff --git a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt
index 0dd9a597e9663..0c55ba75f137f 100644
--- a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt
+++ b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt
@@ -1,11 +1,18 @@
tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(6,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
-tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(14,12): error TS2503: Cannot find namespace 'Foo'.
-tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(22,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
-tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(29,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
-tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702: 'Foo' only refers to a type, but is being used as a namespace here.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(7,18): error TS2694: Namespace 'Test1' has no exported member 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(15,12): error TS2503: Cannot find namespace 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(16,18): error TS2694: Namespace 'Test2' has no exported member 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(24,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(25,18): error TS2694: Namespace 'Test3' has no exported member 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(32,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(33,18): error TS2694: Namespace 'Test4' has no exported member 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(40,12): error TS2702: 'Foo' only refers to a type, but is being used as a namespace here.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(41,18): error TS2694: Namespace 'Test5' has no exported member 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,20): error TS2694: Namespace 'Test5' has no exported member 'Foo'.
+tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003: Identifier expected.
-==== tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts (5 errors) ====
+==== tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts (12 errors) ====
namespace Test1 {
export interface Foo {
bar: string;
@@ -14,6 +21,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702
var x: Foo.bar = "";
~~~~~~~
!!! error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
+ var y: Test1.Foo.bar = "";
+ ~~~
+!!! error TS2694: Namespace 'Test1' has no exported member 'Foo'.
}
namespace Test2 {
@@ -24,6 +34,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702
var x: Foo.bar = "";
~~~
!!! error TS2503: Cannot find namespace 'Foo'.
+ var y: Test2.Foo.bar = "";
+ ~~~
+!!! error TS2694: Namespace 'Test2' has no exported member 'Foo'.
}
namespace Test3 {
@@ -34,6 +47,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702
var x: Foo.bar = "";
~~~~~~~
!!! error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
+ var y: Test3.Foo.bar = "";
+ ~~~
+!!! error TS2694: Namespace 'Test3' has no exported member 'Foo'.
}
namespace Test4 {
@@ -43,6 +59,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702
var x: Foo.bar = "";
~~~~~~~
!!! error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'?
+ var y: Test4.Foo.bar = "";
+ ~~~
+!!! error TS2694: Namespace 'Test4' has no exported member 'Foo'.
}
namespace Test5 {
@@ -52,4 +71,13 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702
var x: Foo.bar = "";
~~~
!!! error TS2702: 'Foo' only refers to a type, but is being used as a namespace here.
- }
\ No newline at end of file
+ var y: Test5.Foo.bar = "";
+ ~~~
+!!! error TS2694: Namespace 'Test5' has no exported member 'Foo'.
+ }
+
+ import lol = Test5.Foo.
+ ~~~
+!!! error TS2694: Namespace 'Test5' has no exported member 'Foo'.
+
+!!! error TS1003: Identifier expected.
\ No newline at end of file
diff --git a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js
index 8a70396880bec..26903a97989da 100644
--- a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js
+++ b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js
@@ -5,6 +5,7 @@ namespace Test1 {
}
var x: Foo.bar = "";
+ var y: Test1.Foo.bar = "";
}
namespace Test2 {
@@ -13,6 +14,7 @@ namespace Test2 {
}
var x: Foo.bar = "";
+ var y: Test2.Foo.bar = "";
}
namespace Test3 {
@@ -21,6 +23,7 @@ namespace Test3 {
}
var x: Foo.bar = "";
+ var y: Test3.Foo.bar = "";
}
namespace Test4 {
@@ -28,6 +31,7 @@ namespace Test4 {
| { bar: string }
var x: Foo.bar = "";
+ var y: Test4.Foo.bar = "";
}
namespace Test5 {
@@ -35,12 +39,16 @@ namespace Test5 {
| { wat: string }
var x: Foo.bar = "";
-}
+ var y: Test5.Foo.bar = "";
+}
+
+import lol = Test5.Foo.
//// [errorForUsingPropertyOfTypeAsType01.js]
var Test1;
(function (Test1) {
var x = "";
+ var y = "";
})(Test1 || (Test1 = {}));
var Test2;
(function (Test2) {
@@ -51,16 +59,21 @@ var Test2;
}());
Test2.Foo = Foo;
var x = "";
+ var y = "";
})(Test2 || (Test2 = {}));
var Test3;
(function (Test3) {
var x = "";
+ var y = "";
})(Test3 || (Test3 = {}));
var Test4;
(function (Test4) {
var x = "";
+ var y = "";
})(Test4 || (Test4 = {}));
var Test5;
(function (Test5) {
var x = "";
+ var y = "";
})(Test5 || (Test5 = {}));
+var lol = Test5.Foo.;
diff --git a/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts b/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts
index c20102881eae0..8ce16b6fcd712 100644
--- a/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts
+++ b/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts
@@ -4,6 +4,7 @@ namespace Test1 {
}
var x: Foo.bar = "";
+ var y: Test1.Foo.bar = "";
}
namespace Test2 {
@@ -12,6 +13,7 @@ namespace Test2 {
}
var x: Foo.bar = "";
+ var y: Test2.Foo.bar = "";
}
namespace Test3 {
@@ -20,6 +22,7 @@ namespace Test3 {
}
var x: Foo.bar = "";
+ var y: Test3.Foo.bar = "";
}
namespace Test4 {
@@ -27,6 +30,7 @@ namespace Test4 {
| { bar: string }
var x: Foo.bar = "";
+ var y: Test4.Foo.bar = "";
}
namespace Test5 {
@@ -34,4 +38,7 @@ namespace Test5 {
| { wat: string }
var x: Foo.bar = "";
-}
\ No newline at end of file
+ var y: Test5.Foo.bar = "";
+}
+
+import lol = Test5.Foo.
\ No newline at end of file
diff --git a/tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts b/tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts
new file mode 100644
index 0000000000000..683e45f056a46
--- /dev/null
+++ b/tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts
@@ -0,0 +1,11 @@
+///
+
+
+//// namespace Container {
+//// export interface Foo {
+//// bar: string;
+//// }
+//// }
+//// const x: [|Container.Foo.bar|] = ""
+
+verify.not.codeFixAvailable();
diff --git a/tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts b/tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts
new file mode 100644
index 0000000000000..ffcc9ffeacc61
--- /dev/null
+++ b/tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts
@@ -0,0 +1,8 @@
+///
+
+//// export interface Foo {
+//// bar: string;
+//// }
+//// const x: [|Foo.bar|] = ""
+
+verify.rangeAfterCodeFix(`Foo["bar"]`);