Skip to content

Commit 59d027b

Browse files
committed
Show elaboration for property not existing in union
Fixes #10256. Accessing a non-existant property on union types should now show an elaboration in the error message specifying the first constituent type that lacks the property.
1 parent 598ca48 commit 59d027b

6 files changed

+43
-3
lines changed

src/compiler/checker.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -10773,7 +10773,7 @@ namespace ts {
1077310773
const prop = getPropertyOfType(apparentType, right.text);
1077410774
if (!prop) {
1077510775
if (right.text && !checkAndReportErrorForExtendingInterface(node)) {
10776-
error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type.flags & TypeFlags.ThisType ? apparentType : type));
10776+
reportNonexistantProperty(right, type.flags & TypeFlags.ThisType ? apparentType : type);
1077710777
}
1077810778
return unknownType;
1077910779
}
@@ -10810,6 +10810,20 @@ namespace ts {
1081010810
return propType;
1081110811
}
1081210812
return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
10813+
10814+
function reportNonexistantProperty(propNode: Identifier, containingType: Type) {
10815+
let errorInfo: DiagnosticMessageChain;
10816+
if (containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Enum)) {
10817+
for (const subtype of (containingType as UnionType).types) {
10818+
if (!getPropertyOfType(subtype, propNode.text)) {
10819+
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype));
10820+
break;
10821+
}
10822+
}
10823+
}
10824+
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
10825+
diagnostics.add(createDiagnosticForNodeFromMessageChain(propNode, errorInfo));
10826+
}
1081310827
}
1081410828

1081510829
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
tests/cases/compiler/propertyAccess3.ts(2,5): error TS2339: Property 'toBAZ' does not exist on type 'boolean'.
2+
Property 'toBAZ' does not exist on type 'true'.
23

34

45
==== tests/cases/compiler/propertyAccess3.ts (1 errors) ====
56
var foo: boolean;
67
foo.toBAZ();
78
~~~~~
8-
!!! error TS2339: Property 'toBAZ' does not exist on type 'boolean'.
9+
!!! error TS2339: Property 'toBAZ' does not exist on type 'boolean'.
10+
!!! error TS2339: Property 'toBAZ' does not exist on type 'true'.

tests/baselines/reference/typeGuardsWithAny.errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(11,7): error TS2339: Property 'p' does not exist on type 'string'.
22
tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(18,7): error TS2339: Property 'p' does not exist on type 'number'.
33
tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(25,7): error TS2339: Property 'p' does not exist on type 'boolean'.
4+
Property 'p' does not exist on type 'true'.
45

56

67
==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts (3 errors) ====
@@ -35,6 +36,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(25,7): error
3536
x.p; // Error, type any narrowed by primitive type check
3637
~
3738
!!! error TS2339: Property 'p' does not exist on type 'boolean'.
39+
!!! error TS2339: Property 'p' does not exist on type 'true'.
3840
}
3941
else {
4042
x.p; // No error, type unaffected in this branch

tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt

+12
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
55
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(41,10): error TS2339: Property 'bar' does not exist on type 'B<any>'.
66
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(66,10): error TS2339: Property 'bar2' does not exist on type 'C1'.
77
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(72,10): error TS2339: Property 'bar1' does not exist on type 'C1 | C2'.
8+
Property 'bar1' does not exist on type 'C2'.
89
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(73,10): error TS2339: Property 'bar2' does not exist on type 'C1 | C2'.
10+
Property 'bar2' does not exist on type 'C1'.
911
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(85,10): error TS2339: Property 'bar' does not exist on type 'D'.
1012
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(91,10): error TS2339: Property 'bar' does not exist on type 'D'.
1113
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(112,10): error TS2339: Property 'bar2' does not exist on type 'E1'.
1214
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(118,11): error TS2339: Property 'bar1' does not exist on type 'E1 | E2'.
15+
Property 'bar1' does not exist on type 'E2'.
1316
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(119,11): error TS2339: Property 'bar2' does not exist on type 'E1 | E2'.
17+
Property 'bar2' does not exist on type 'E1'.
1418
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(134,11): error TS2339: Property 'foo' does not exist on type 'string | F'.
19+
Property 'foo' does not exist on type 'string'.
1520
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(135,11): error TS2339: Property 'bar' does not exist on type 'string | F'.
21+
Property 'bar' does not exist on type 'string'.
1622
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(160,11): error TS2339: Property 'foo2' does not exist on type 'G1'.
1723
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(166,11): error TS2339: Property 'foo2' does not exist on type 'G1'.
1824
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(182,11): error TS2339: Property 'bar' does not exist on type 'H'.
@@ -107,9 +113,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
107113
obj6.bar1;
108114
~~~~
109115
!!! error TS2339: Property 'bar1' does not exist on type 'C1 | C2'.
116+
!!! error TS2339: Property 'bar1' does not exist on type 'C2'.
110117
obj6.bar2;
111118
~~~~
112119
!!! error TS2339: Property 'bar2' does not exist on type 'C1 | C2'.
120+
!!! error TS2339: Property 'bar2' does not exist on type 'C1'.
113121
}
114122

115123
// with object type literal
@@ -163,9 +171,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
163171
obj10.bar1;
164172
~~~~
165173
!!! error TS2339: Property 'bar1' does not exist on type 'E1 | E2'.
174+
!!! error TS2339: Property 'bar1' does not exist on type 'E2'.
166175
obj10.bar2;
167176
~~~~
168177
!!! error TS2339: Property 'bar2' does not exist on type 'E1 | E2'.
178+
!!! error TS2339: Property 'bar2' does not exist on type 'E1'.
169179
}
170180

171181
// a construct signature that returns any
@@ -183,9 +193,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
183193
obj11.foo;
184194
~~~
185195
!!! error TS2339: Property 'foo' does not exist on type 'string | F'.
196+
!!! error TS2339: Property 'foo' does not exist on type 'string'.
186197
obj11.bar;
187198
~~~
188199
!!! error TS2339: Property 'bar' does not exist on type 'string | F'.
200+
!!! error TS2339: Property 'bar' does not exist on type 'string'.
189201
}
190202

191203
var obj12: any;

tests/baselines/reference/unionTypeMembers.errors.txt

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
tests/cases/conformance/types/union/unionTypeMembers.ts(44,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
22
tests/cases/conformance/types/union/unionTypeMembers.ts(51,3): error TS2339: Property 'propertyOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
3+
Property 'propertyOnlyInI1' does not exist on type 'I2<number>'.
34
tests/cases/conformance/types/union/unionTypeMembers.ts(52,3): error TS2339: Property 'propertyOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
5+
Property 'propertyOnlyInI2' does not exist on type 'I1<number>'.
46
tests/cases/conformance/types/union/unionTypeMembers.ts(53,3): error TS2339: Property 'methodOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
7+
Property 'methodOnlyInI1' does not exist on type 'I2<number>'.
58
tests/cases/conformance/types/union/unionTypeMembers.ts(54,3): error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
9+
Property 'methodOnlyInI2' does not exist on type 'I1<number>'.
610

711

812
==== tests/cases/conformance/types/union/unionTypeMembers.ts (5 errors) ====
@@ -61,12 +65,16 @@ tests/cases/conformance/types/union/unionTypeMembers.ts(54,3): error TS2339: Pro
6165
x.propertyOnlyInI1; // error
6266
~~~~~~~~~~~~~~~~
6367
!!! error TS2339: Property 'propertyOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
68+
!!! error TS2339: Property 'propertyOnlyInI1' does not exist on type 'I2<number>'.
6469
x.propertyOnlyInI2; // error
6570
~~~~~~~~~~~~~~~~
6671
!!! error TS2339: Property 'propertyOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
72+
!!! error TS2339: Property 'propertyOnlyInI2' does not exist on type 'I1<number>'.
6773
x.methodOnlyInI1("hello"); // error
6874
~~~~~~~~~~~~~~
6975
!!! error TS2339: Property 'methodOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
76+
!!! error TS2339: Property 'methodOnlyInI1' does not exist on type 'I2<number>'.
7077
x.methodOnlyInI2(10); // error
7178
~~~~~~~~~~~~~~
72-
!!! error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
79+
!!! error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
80+
!!! error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number>'.

tests/baselines/reference/unionTypeReadonly.errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ tests/cases/conformance/types/union/unionTypeReadonly.ts(19,1): error TS2450: Le
33
tests/cases/conformance/types/union/unionTypeReadonly.ts(21,1): error TS2450: Left-hand side of assignment expression cannot be a constant or a read-only property.
44
tests/cases/conformance/types/union/unionTypeReadonly.ts(23,1): error TS2450: Left-hand side of assignment expression cannot be a constant or a read-only property.
55
tests/cases/conformance/types/union/unionTypeReadonly.ts(25,15): error TS2339: Property 'value' does not exist on type 'Base | DifferentName'.
6+
Property 'value' does not exist on type 'DifferentName'.
67

78

89
==== tests/cases/conformance/types/union/unionTypeReadonly.ts (5 errors) ====
@@ -41,5 +42,6 @@ tests/cases/conformance/types/union/unionTypeReadonly.ts(25,15): error TS2339: P
4142
differentName.value = 12; // error, property 'value' doesn't exist
4243
~~~~~
4344
!!! error TS2339: Property 'value' does not exist on type 'Base | DifferentName'.
45+
!!! error TS2339: Property 'value' does not exist on type 'DifferentName'.
4446

4547

0 commit comments

Comments
 (0)