improve error message for using property of type as type (#45354)

* improve error message for using property of type as type

* suggest typeof when possible

* fix naming and error location
This commit is contained in:
Zzzen 2021-09-04 03:17:50 +08:00 committed by GitHub
parent d514a69409
commit 1d51dfa550
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 37 deletions

View file

@ -3156,6 +3156,30 @@ namespace ts {
return symbol.parent ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) : symbolToString(symbol, containingLocation, /*meaning*/ undefined, SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind);
}
function getContainingQualifiedNameNode(node: QualifiedName) {
while (isQualifiedName(node.parent)) {
node = node.parent;
}
return node;
}
function tryGetQualifiedNameAsValue(node: QualifiedName) {
let left: Identifier | QualifiedName = getFirstIdentifier(node);
let symbol = resolveName(left, left.escapedText, SymbolFlags.Value, undefined, left, /*isUse*/ true);
if (!symbol) {
return undefined;
}
while (isQualifiedName(left.parent)) {
const type = getTypeOfSymbol(symbol);
symbol = getPropertyOfType(type, left.parent.right.escapedText);
if (!symbol) {
return undefined;
}
left = left.parent;
}
return symbol;
}
/**
* Resolves a qualified name and any involved aliases.
*/
@ -3205,10 +3229,22 @@ namespace ts {
if (!ignoreErrors) {
const namespaceName = getFullyQualifiedName(namespace);
const declarationName = declarationNameToString(right);
const suggestion = getSuggestedSymbolForNonexistentModule(right, namespace);
suggestion ?
error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestion)) :
const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace);
const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type));
const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name);
const canSuggestTypeof = containingQualifiedName && !isTypeOfExpression(containingQualifiedName.parent) && tryGetQualifiedNameAsValue(containingQualifiedName);
if (suggestionForNonexistentModule) {
error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule));
}
else if (canSuggestTypeof) {
error(containingQualifiedName, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, entityNameToString(containingQualifiedName));
}
else if (meaning & SymbolFlags.Namespace && exportedTypeSymbol && isQualifiedName(name.parent)) {
error(name.parent.right, 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, symbolToString(exportedTypeSymbol), unescapeLeadingUnderscores(name.parent.right.escapedText));
}
else {
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
}
}
return undefined;
}

View file

@ -1,15 +1,15 @@
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(7,18): error TS2694: Namespace 'Test1' has no exported member 'Foo'.
tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(7,22): 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(15,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(16,18): error TS2694: Namespace 'Test2' has no exported member 'Foo'.
tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(16,22): 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(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(25,22): 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(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(33,22): 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(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(41,22): 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(44,24): error TS1003: Identifier expected.
tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS2713: Cannot access 'Foo.' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property '' in 'Foo' with 'Foo[""]'?
==== tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts (12 errors) ====
@ -22,8 +22,8 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003
~~~~~~~
!!! 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'.
~~~
!!! 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 {
@ -35,8 +35,8 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003
~~~~~~~
!!! 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: Test2.Foo.bar = "";
~~~
!!! error TS2694: Namespace 'Test2' has no exported member 'Foo'.
~~~
!!! 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 Test3 {
@ -48,8 +48,8 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003
~~~~~~~
!!! 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'.
~~~
!!! 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 {
@ -60,8 +60,8 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003
~~~~~~~
!!! 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'.
~~~
!!! 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 {
@ -72,12 +72,12 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003
~~~
!!! error TS2702: 'Foo' only refers to a type, but is being used as a namespace here.
var y: Test5.Foo.bar = "";
~~~
!!! error TS2694: Namespace 'Test5' has no exported member 'Foo'.
~~~
!!! 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"]'?
}
import lol = Test5.Foo.
~~~
!!! error TS2694: Namespace 'Test5' has no exported member 'Foo'.
!!! error TS1003: Identifier expected.
!!! error TS1003: Identifier expected.
!!! error TS2713: Cannot access 'Foo.' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property '' in 'Foo' with 'Foo[""]'?

View file

@ -1,4 +1,4 @@
tests/cases/compiler/errorForUsingPropertyOfTypeAsType03.ts(11,19): error TS2694: Namespace 'Color' has no exported member 'Red'.
tests/cases/compiler/errorForUsingPropertyOfTypeAsType03.ts(11,13): error TS2749: 'Color.Red.toString' refers to a value, but is being used as a type here. Did you mean 'typeof Color.Red.toString'?
tests/cases/compiler/errorForUsingPropertyOfTypeAsType03.ts(13,19): error TS2339: Property 'Red' does not exist on type 'Color'.
tests/cases/compiler/errorForUsingPropertyOfTypeAsType03.ts(19,13): error TS2702: 'C1' only refers to a type, but is being used as a namespace here.
tests/cases/compiler/errorForUsingPropertyOfTypeAsType03.ts(20,13): error TS2702: 'C1' only refers to a type, but is being used as a namespace here.
@ -19,8 +19,8 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType03.ts(24,13): error TS2713
type C2 = typeof Color;
let a1: Color.Red.toString;
~~~
!!! error TS2694: Namespace 'Color' has no exported member 'Red'.
~~~~~~~~~~~~~~~~~~
!!! error TS2749: 'Color.Red.toString' refers to a value, but is being used as a type here. Did you mean 'typeof Color.Red.toString'?
let a2: Color.Red["toString"];
let a3: Color["Red"]["toString"];
~~~~~

View file

@ -1,4 +1,4 @@
tests/cases/compiler/genericFunduleInModule.ts(8,10): error TS2694: Namespace 'A' has no exported member 'B'.
tests/cases/compiler/genericFunduleInModule.ts(8,8): error TS2749: 'A.B' refers to a value, but is being used as a type here. Did you mean 'typeof A.B'?
==== tests/cases/compiler/genericFunduleInModule.ts (1 errors) ====
@ -10,6 +10,6 @@ tests/cases/compiler/genericFunduleInModule.ts(8,10): error TS2694: Namespace 'A
}
var b: A.B;
~
!!! error TS2694: Namespace 'A' has no exported member 'B'.
~~~
!!! error TS2749: 'A.B' refers to a value, but is being used as a type here. Did you mean 'typeof A.B'?
A.B(1);

View file

@ -1,4 +1,4 @@
tests/cases/compiler/genericFunduleInModule2.ts(11,10): error TS2694: Namespace 'A' has no exported member 'B'.
tests/cases/compiler/genericFunduleInModule2.ts(11,8): error TS2749: 'A.B' refers to a value, but is being used as a type here. Did you mean 'typeof A.B'?
==== tests/cases/compiler/genericFunduleInModule2.ts (1 errors) ====
@ -13,6 +13,6 @@ tests/cases/compiler/genericFunduleInModule2.ts(11,10): error TS2694: Namespace
}
var b: A.B;
~
!!! error TS2694: Namespace 'A' has no exported member 'B'.
~~~
!!! error TS2749: 'A.B' refers to a value, but is being used as a type here. Did you mean 'typeof A.B'?
A.B(1);

View file

@ -1,6 +1,6 @@
/b.ts(2,1): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
/b.ts(3,1): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
/b.ts(4,14): error TS2694: Namespace '"/a"' has no exported member 'Value'.
/b.ts(4,8): error TS2749: 'types.Value' refers to a value, but is being used as a type here. Did you mean 'typeof types.Value'?
/b.ts(5,7): error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.
/b.ts(6,7): error TS2741: Property 'b' is missing in type '{}' but required in type 'B'.
/b.ts(8,13): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
@ -23,8 +23,8 @@
!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
!!! related TS1376 /b.ts:1:18: 'types' was imported here.
let v: types.Value;
~~~~~
!!! error TS2694: Namespace '"/a"' has no exported member 'Value'.
~~~~~~~~~~~
!!! error TS2749: 'types.Value' refers to a value, but is being used as a type here. Did you mean 'typeof types.Value'?
const a: types.A = {};
~
!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'A'.

View file

@ -2,7 +2,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(16,21): er
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(17,21): error TS6053: File 'tests/cases/conformance/parser/ecmascript5/compiler/typescript.ts' not found.
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(18,21): error TS6053: File 'tests/cases/conformance/parser/ecmascript5/services/typescriptServices.ts' not found.
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(19,21): error TS6053: File 'tests/cases/conformance/parser/ecmascript5/RealWorld/diff.ts' not found.
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(21,29): error TS2694: Namespace 'Harness' has no exported member 'Assert'.
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(21,21): error TS2749: 'Harness.Assert' refers to a value, but is being used as a type here. Did you mean 'typeof Harness.Assert'?
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(25,17): error TS2304: Cannot find name 'IIO'.
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(41,12): error TS2304: Cannot find name 'ActiveXObject'.
tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(43,19): error TS2580: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
@ -140,8 +140,8 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32):
!!! error TS6053: File 'tests/cases/conformance/parser/ecmascript5/RealWorld/diff.ts' not found.
declare var assert: Harness.Assert;
~~~~~~
!!! error TS2694: Namespace 'Harness' has no exported member 'Assert'.
~~~~~~~~~~~~~~
!!! error TS2749: 'Harness.Assert' refers to a value, but is being used as a type here. Did you mean 'typeof Harness.Assert'?
declare var it;
declare var describe;
declare var run;