diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fcfee1b468477..40d973ca9cef7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1240,7 +1240,22 @@ namespace ts { function checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { if (meaning === SymbolFlags.Namespace) { const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined)); + const parent = errorLocation.parent; if (symbol) { + if (isQualifiedName(parent)) { + Debug.assert(parent.left === errorLocation, "Should only be resolving left side of qualified name as a namespace"); + const propName = parent.right.escapedText; + const propType = getPropertyOfType(getDeclaredTypeOfSymbol(symbol), propName); + if (propType) { + error( + parent, + 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, + unescapeLeadingUnderscores(name), + unescapeLeadingUnderscores(propName), + ); + return true; + } + } error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, unescapeLeadingUnderscores(name)); return true; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7cd6108576cc2..0d9e7a0a6bf09 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2192,6 +2192,10 @@ "category": "Error", "code": 2712 }, + "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}\"]'?": { + "category": "Error", + "code": 2713 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt new file mode 100644 index 0000000000000..0dd9a597e9663 --- /dev/null +++ b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt @@ -0,0 +1,55 @@ +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 (5 errors) ==== + namespace Test1 { + export interface Foo { + bar: string; + } + + 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"]'? + } + + namespace Test2 { + export class Foo { + bar: string; + } + + var x: Foo.bar = ""; + ~~~ +!!! error TS2503: Cannot find namespace 'Foo'. + } + + namespace Test3 { + export type Foo = { + bar: string; + } + + 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"]'? + } + + namespace Test4 { + export type Foo = { bar: number } + | { bar: string } + + 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"]'? + } + + namespace Test5 { + export type Foo = { bar: number } + | { wat: string } + + 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 diff --git a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js new file mode 100644 index 0000000000000..8a70396880bec --- /dev/null +++ b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js @@ -0,0 +1,66 @@ +//// [errorForUsingPropertyOfTypeAsType01.ts] +namespace Test1 { + export interface Foo { + bar: string; + } + + var x: Foo.bar = ""; +} + +namespace Test2 { + export class Foo { + bar: string; + } + + var x: Foo.bar = ""; +} + +namespace Test3 { + export type Foo = { + bar: string; + } + + var x: Foo.bar = ""; +} + +namespace Test4 { + export type Foo = { bar: number } + | { bar: string } + + var x: Foo.bar = ""; +} + +namespace Test5 { + export type Foo = { bar: number } + | { wat: string } + + var x: Foo.bar = ""; +} + +//// [errorForUsingPropertyOfTypeAsType01.js] +var Test1; +(function (Test1) { + var x = ""; +})(Test1 || (Test1 = {})); +var Test2; +(function (Test2) { + var Foo = (function () { + function Foo() { + } + return Foo; + }()); + Test2.Foo = Foo; + var x = ""; +})(Test2 || (Test2 = {})); +var Test3; +(function (Test3) { + var x = ""; +})(Test3 || (Test3 = {})); +var Test4; +(function (Test4) { + var x = ""; +})(Test4 || (Test4 = {})); +var Test5; +(function (Test5) { + var x = ""; +})(Test5 || (Test5 = {})); diff --git a/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts b/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts new file mode 100644 index 0000000000000..c20102881eae0 --- /dev/null +++ b/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts @@ -0,0 +1,37 @@ +namespace Test1 { + export interface Foo { + bar: string; + } + + var x: Foo.bar = ""; +} + +namespace Test2 { + export class Foo { + bar: string; + } + + var x: Foo.bar = ""; +} + +namespace Test3 { + export type Foo = { + bar: string; + } + + var x: Foo.bar = ""; +} + +namespace Test4 { + export type Foo = { bar: number } + | { bar: string } + + var x: Foo.bar = ""; +} + +namespace Test5 { + export type Foo = { bar: number } + | { wat: string } + + var x: Foo.bar = ""; +} \ No newline at end of file