Merge pull request #10582 from oijazsh/TS2339

Show an elaboration when accessing a non-existent property of a union type
This commit is contained in:
Mohamed Hegazy 2016-09-13 13:57:14 -07:00 committed by GitHub
commit a612d586c6
7 changed files with 219 additions and 2 deletions

View File

@ -10869,7 +10869,7 @@ namespace ts {
const prop = getPropertyOfType(apparentType, right.text);
if (!prop) {
if (right.text && !checkAndReportErrorForExtendingInterface(node)) {
error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type.flags & TypeFlags.ThisType ? apparentType : type));
reportNonexistentProperty(right, type.flags & TypeFlags.ThisType ? apparentType : type);
}
return unknownType;
}
@ -10903,6 +10903,20 @@ namespace ts {
return propType;
}
return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
function reportNonexistentProperty(propNode: Identifier, containingType: Type) {
let errorInfo: DiagnosticMessageChain;
if (containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) {
for (const subtype of (containingType as UnionType).types) {
if (!getPropertyOfType(subtype, propNode.text)) {
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype));
break;
}
}
}
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
diagnostics.add(createDiagnosticForNodeFromMessageChain(propNode, errorInfo));
}
}
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {

View File

@ -5,14 +5,20 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(41,10): error TS2339: Property 'bar' does not exist on type 'B<any>'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(66,10): error TS2339: Property 'bar2' does not exist on type 'C1'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(72,10): error TS2339: Property 'bar1' does not exist on type 'C1 | C2'.
Property 'bar1' does not exist on type 'C2'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(73,10): error TS2339: Property 'bar2' does not exist on type 'C1 | C2'.
Property 'bar2' does not exist on type 'C1'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(85,10): error TS2339: Property 'bar' does not exist on type 'D'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(91,10): error TS2339: Property 'bar' does not exist on type 'D'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(112,10): error TS2339: Property 'bar2' does not exist on type 'E1'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(118,11): error TS2339: Property 'bar1' does not exist on type 'E1 | E2'.
Property 'bar1' does not exist on type 'E2'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(119,11): error TS2339: Property 'bar2' does not exist on type 'E1 | E2'.
Property 'bar2' does not exist on type 'E1'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(134,11): error TS2339: Property 'foo' does not exist on type 'string | F'.
Property 'foo' does not exist on type 'string'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(135,11): error TS2339: Property 'bar' does not exist on type 'string | F'.
Property 'bar' does not exist on type 'string'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(160,11): error TS2339: Property 'foo2' does not exist on type 'G1'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(166,11): error TS2339: Property 'foo2' does not exist on type 'G1'.
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
obj6.bar1;
~~~~
!!! error TS2339: Property 'bar1' does not exist on type 'C1 | C2'.
!!! error TS2339: Property 'bar1' does not exist on type 'C2'.
obj6.bar2;
~~~~
!!! error TS2339: Property 'bar2' does not exist on type 'C1 | C2'.
!!! error TS2339: Property 'bar2' does not exist on type 'C1'.
}
// with object type literal
@ -163,9 +171,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
obj10.bar1;
~~~~
!!! error TS2339: Property 'bar1' does not exist on type 'E1 | E2'.
!!! error TS2339: Property 'bar1' does not exist on type 'E2'.
obj10.bar2;
~~~~
!!! error TS2339: Property 'bar2' does not exist on type 'E1 | E2'.
!!! error TS2339: Property 'bar2' does not exist on type 'E1'.
}
// a construct signature that returns any
@ -183,9 +193,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
obj11.foo;
~~~
!!! error TS2339: Property 'foo' does not exist on type 'string | F'.
!!! error TS2339: Property 'foo' does not exist on type 'string'.
obj11.bar;
~~~
!!! error TS2339: Property 'bar' does not exist on type 'string | F'.
!!! error TS2339: Property 'bar' does not exist on type 'string'.
}
var obj12: any;

View File

@ -0,0 +1,84 @@
tests/cases/compiler/unionPropertyExistence.ts(27,3): error TS2339: Property 'nope' does not exist on type '"foo" | "bar"'.
Property 'nope' does not exist on type '"foo"'.
tests/cases/compiler/unionPropertyExistence.ts(28,6): error TS2339: Property 'onlyInB' does not exist on type 'B | "foo"'.
Property 'onlyInB' does not exist on type '"foo"'.
tests/cases/compiler/unionPropertyExistence.ts(30,6): error TS2339: Property 'length' does not exist on type 'B | "foo"'.
Property 'length' does not exist on type 'B'.
tests/cases/compiler/unionPropertyExistence.ts(32,4): error TS2339: Property 'onlyInB' does not exist on type 'AB'.
Property 'onlyInB' does not exist on type 'A'.
tests/cases/compiler/unionPropertyExistence.ts(35,5): error TS2339: Property 'notInC' does not exist on type 'ABC'.
Property 'notInC' does not exist on type 'C'.
tests/cases/compiler/unionPropertyExistence.ts(36,4): error TS2339: Property 'notInB' does not exist on type 'AB'.
Property 'notInB' does not exist on type 'B'.
tests/cases/compiler/unionPropertyExistence.ts(37,5): error TS2339: Property 'notInB' does not exist on type 'ABC'.
Property 'notInB' does not exist on type 'B'.
tests/cases/compiler/unionPropertyExistence.ts(40,5): error TS2339: Property 'inNone' does not exist on type 'ABC'.
Property 'inNone' does not exist on type 'A'.
==== tests/cases/compiler/unionPropertyExistence.ts (8 errors) ====
interface A {
inAll: string;
notInB: string;
notInC: string;
}
interface B {
inAll: boolean;
onlyInB: number;
notInC: string;
}
interface C {
inAll: number;
notInB: string;
}
type AB = A | B;
type ABC = C | AB;
var ab: AB;
var abc: ABC;
declare const x: "foo" | "bar";
declare const bFoo: B | "foo";
x.nope();
~~~~
!!! error TS2339: Property 'nope' does not exist on type '"foo" | "bar"'.
!!! error TS2339: Property 'nope' does not exist on type '"foo"'.
bFoo.onlyInB;
~~~~~~~
!!! error TS2339: Property 'onlyInB' does not exist on type 'B | "foo"'.
!!! error TS2339: Property 'onlyInB' does not exist on type '"foo"'.
x.length; // Ok
bFoo.length;
~~~~~~
!!! error TS2339: Property 'length' does not exist on type 'B | "foo"'.
!!! error TS2339: Property 'length' does not exist on type 'B'.
ab.onlyInB;
~~~~~~~
!!! error TS2339: Property 'onlyInB' does not exist on type 'AB'.
!!! error TS2339: Property 'onlyInB' does not exist on type 'A'.
ab.notInC; // Ok
abc.notInC;
~~~~~~
!!! error TS2339: Property 'notInC' does not exist on type 'ABC'.
!!! error TS2339: Property 'notInC' does not exist on type 'C'.
ab.notInB;
~~~~~~
!!! error TS2339: Property 'notInB' does not exist on type 'AB'.
!!! error TS2339: Property 'notInB' does not exist on type 'B'.
abc.notInB;
~~~~~~
!!! error TS2339: Property 'notInB' does not exist on type 'ABC'.
!!! error TS2339: Property 'notInB' does not exist on type 'B'.
abc.inAll; // Ok
abc.inNone;
~~~~~~
!!! error TS2339: Property 'inNone' does not exist on type 'ABC'.
!!! error TS2339: Property 'inNone' does not exist on type 'A'.

View File

@ -0,0 +1,57 @@
//// [unionPropertyExistence.ts]
interface A {
inAll: string;
notInB: string;
notInC: string;
}
interface B {
inAll: boolean;
onlyInB: number;
notInC: string;
}
interface C {
inAll: number;
notInB: string;
}
type AB = A | B;
type ABC = C | AB;
var ab: AB;
var abc: ABC;
declare const x: "foo" | "bar";
declare const bFoo: B | "foo";
x.nope();
bFoo.onlyInB;
x.length; // Ok
bFoo.length;
ab.onlyInB;
ab.notInC; // Ok
abc.notInC;
ab.notInB;
abc.notInB;
abc.inAll; // Ok
abc.inNone;
//// [unionPropertyExistence.js]
var ab;
var abc;
x.nope();
bFoo.onlyInB;
x.length; // Ok
bFoo.length;
ab.onlyInB;
ab.notInC; // Ok
abc.notInC;
ab.notInB;
abc.notInB;
abc.inAll; // Ok
abc.inNone;

View File

@ -1,8 +1,12 @@
tests/cases/conformance/types/union/unionTypeMembers.ts(44,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeMembers.ts(51,3): error TS2339: Property 'propertyOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
Property 'propertyOnlyInI1' does not exist on type 'I2<number>'.
tests/cases/conformance/types/union/unionTypeMembers.ts(52,3): error TS2339: Property 'propertyOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
Property 'propertyOnlyInI2' does not exist on type 'I1<number>'.
tests/cases/conformance/types/union/unionTypeMembers.ts(53,3): error TS2339: Property 'methodOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
Property 'methodOnlyInI1' does not exist on type 'I2<number>'.
tests/cases/conformance/types/union/unionTypeMembers.ts(54,3): error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
Property 'methodOnlyInI2' does not exist on type 'I1<number>'.
==== 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
x.propertyOnlyInI1; // error
~~~~~~~~~~~~~~~~
!!! error TS2339: Property 'propertyOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
!!! error TS2339: Property 'propertyOnlyInI1' does not exist on type 'I2<number>'.
x.propertyOnlyInI2; // error
~~~~~~~~~~~~~~~~
!!! error TS2339: Property 'propertyOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
!!! error TS2339: Property 'propertyOnlyInI2' does not exist on type 'I1<number>'.
x.methodOnlyInI1("hello"); // error
~~~~~~~~~~~~~~
!!! error TS2339: Property 'methodOnlyInI1' does not exist on type 'I1<number> | I2<number>'.
!!! error TS2339: Property 'methodOnlyInI1' does not exist on type 'I2<number>'.
x.methodOnlyInI2(10); // error
~~~~~~~~~~~~~~
!!! error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
!!! error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number> | I2<number>'.
!!! error TS2339: Property 'methodOnlyInI2' does not exist on type 'I1<number>'.

View File

@ -3,6 +3,7 @@ tests/cases/conformance/types/union/unionTypeReadonly.ts(19,1): error TS2450: Le
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.
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.
tests/cases/conformance/types/union/unionTypeReadonly.ts(25,15): error TS2339: Property 'value' does not exist on type 'Base | DifferentName'.
Property 'value' does not exist on type 'DifferentName'.
==== 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
differentName.value = 12; // error, property 'value' doesn't exist
~~~~~
!!! error TS2339: Property 'value' does not exist on type 'Base | DifferentName'.
!!! error TS2339: Property 'value' does not exist on type 'DifferentName'.

View File

@ -0,0 +1,40 @@
interface A {
inAll: string;
notInB: string;
notInC: string;
}
interface B {
inAll: boolean;
onlyInB: number;
notInC: string;
}
interface C {
inAll: number;
notInB: string;
}
type AB = A | B;
type ABC = C | AB;
var ab: AB;
var abc: ABC;
declare const x: "foo" | "bar";
declare const bFoo: B | "foo";
x.nope();
bFoo.onlyInB;
x.length; // Ok
bFoo.length;
ab.onlyInB;
ab.notInC; // Ok
abc.notInC;
ab.notInB;
abc.notInB;
abc.inAll; // Ok
abc.inNone;