Skip to content

Stop elaborating errors when relating intersection constituents #7203

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 25, 2016
16 changes: 14 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5521,8 +5521,20 @@ namespace ts {
// on either side that need to be prioritized. For example, A | B = (A | B) & (C | D) or
// A & B = (A & B) | (C & D).
if (source.flags & TypeFlags.Intersection) {
// If target is a union type the following check will report errors so we suppress them here
if (result = someTypeRelatedToType(<IntersectionType>source, target, reportErrors && !(target.flags & TypeFlags.Union))) {
// Check to see if any constituents of the intersection are immediately related to the target.
//
// Don't report errors though. Checking whether a constituent is related to the source is not actually
// useful and leads to some confusing error messages. Instead it is better to let the below checks
// take care of this, or to not elaborate at all. For instance,
//
// - For an object type (such as 'C = A & B'), users are usually more interested in structural errors.
//
// - For a union type (such as '(A | B) = (C & D)'), it's better to hold onto the whole intersection
// than to report that 'D' is not assignable to 'A' or 'B'.
//
// - For a primitive type or type parameter (such as 'number = A & B') there is no point in
// breaking the intersection apart.
if (result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false)) {
return result;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/tsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ namespace ts {
function isJSONSupported() {
return typeof JSON === "object" && typeof JSON.parse === "function";
}
function isWatchSet(options: CompilerOptions) {

function isWatchSet(options: CompilerOptions) {
// Firefox has Object.prototype.watch
return options.watch && options.hasOwnProperty("watch");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
tests/cases/compiler/errorMessagesIntersectionTypes01.ts(14,5): error TS2322: Type '{ fooProp: string; } & Bar' is not assignable to type 'FooBar'.
Types of property 'fooProp' are incompatible.
Type 'string' is not assignable to type 'boolean'.


==== tests/cases/compiler/errorMessagesIntersectionTypes01.ts (1 errors) ====
interface Foo {
fooProp: boolean;
}

interface Bar {
barProp: string;
}

interface FooBar extends Foo, Bar {
}

declare function mixBar<T>(obj: T): T & Bar;

let fooBar: FooBar = mixBar({
~~~~~~
!!! error TS2322: Type '{ fooProp: string; } & Bar' is not assignable to type 'FooBar'.
!!! error TS2322: Types of property 'fooProp' are incompatible.
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
fooProp: "frizzlebizzle"
});
22 changes: 22 additions & 0 deletions tests/baselines/reference/errorMessagesIntersectionTypes01.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [errorMessagesIntersectionTypes01.ts]
interface Foo {
fooProp: boolean;
}

interface Bar {
barProp: string;
}

interface FooBar extends Foo, Bar {
}

declare function mixBar<T>(obj: T): T & Bar;

let fooBar: FooBar = mixBar({
fooProp: "frizzlebizzle"
});

//// [errorMessagesIntersectionTypes01.js]
var fooBar = mixBar({
fooProp: "frizzlebizzle"
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
tests/cases/compiler/errorMessagesIntersectionTypes02.ts(14,5): error TS2322: Type '{ fooProp: string; } & Bar' is not assignable to type 'FooBar'.
Types of property 'fooProp' are incompatible.
Type 'string' is not assignable to type '"hello" | "world"'.
Type 'string' is not assignable to type '"world"'.


==== tests/cases/compiler/errorMessagesIntersectionTypes02.ts (1 errors) ====
interface Foo {
fooProp: "hello" | "world";
}

interface Bar {
barProp: string;
}

interface FooBar extends Foo, Bar {
}

declare function mixBar<T>(obj: T): T & Bar;

let fooBar: FooBar = mixBar({
~~~~~~
!!! error TS2322: Type '{ fooProp: string; } & Bar' is not assignable to type 'FooBar'.
!!! error TS2322: Types of property 'fooProp' are incompatible.
!!! error TS2322: Type 'string' is not assignable to type '"hello" | "world"'.
!!! error TS2322: Type 'string' is not assignable to type '"world"'.
fooProp: "frizzlebizzle"
});
22 changes: 22 additions & 0 deletions tests/baselines/reference/errorMessagesIntersectionTypes02.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [errorMessagesIntersectionTypes02.ts]
interface Foo {
fooProp: "hello" | "world";
}

interface Bar {
barProp: string;
}

interface FooBar extends Foo, Bar {
}

declare function mixBar<T>(obj: T): T & Bar;

let fooBar: FooBar = mixBar({
fooProp: "frizzlebizzle"
});

//// [errorMessagesIntersectionTypes02.js]
var fooBar = mixBar({
fooProp: "frizzlebizzle"
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
tests/cases/compiler/errorMessagesIntersectionTypes03.ts(17,5): error TS2322: Type 'A & B' is not assignable to type 'T'.
tests/cases/compiler/errorMessagesIntersectionTypes03.ts(18,5): error TS2322: Type 'A & B' is not assignable to type 'U'.
tests/cases/compiler/errorMessagesIntersectionTypes03.ts(19,5): error TS2322: Type 'A & B' is not assignable to type 'V'.
tests/cases/compiler/errorMessagesIntersectionTypes03.ts(22,5): error TS2322: Type 'T & B' is not assignable to type 'U'.
tests/cases/compiler/errorMessagesIntersectionTypes03.ts(23,5): error TS2322: Type 'T & B' is not assignable to type 'V'.


==== tests/cases/compiler/errorMessagesIntersectionTypes03.ts (5 errors) ====
interface A {
a;
}

interface B {
b;
}

function f<T, U extends A, V extends U>(): void {
let t: T;
let u: U;
let v: V;

let a_and_b: A & B;
let t_and_b: T & B;

t = a_and_b;
~
!!! error TS2322: Type 'A & B' is not assignable to type 'T'.
u = a_and_b;
~
!!! error TS2322: Type 'A & B' is not assignable to type 'U'.
v = a_and_b;
~
!!! error TS2322: Type 'A & B' is not assignable to type 'V'.

t = t_and_b;
u = t_and_b;
~
!!! error TS2322: Type 'T & B' is not assignable to type 'U'.
v = t_and_b;
~
!!! error TS2322: Type 'T & B' is not assignable to type 'V'.
}
40 changes: 40 additions & 0 deletions tests/baselines/reference/errorMessagesIntersectionTypes03.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//// [errorMessagesIntersectionTypes03.ts]
interface A {
a;
}

interface B {
b;
}

function f<T, U extends A, V extends U>(): void {
let t: T;
let u: U;
let v: V;

let a_and_b: A & B;
let t_and_b: T & B;

t = a_and_b;
u = a_and_b;
v = a_and_b;

t = t_and_b;
u = t_and_b;
v = t_and_b;
}

//// [errorMessagesIntersectionTypes03.js]
function f() {
var t;
var u;
var v;
var a_and_b;
var t_and_b;
t = a_and_b;
u = a_and_b;
v = a_and_b;
t = t_and_b;
u = t_and_b;
v = t_and_b;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
tests/cases/compiler/errorMessagesIntersectionTypes04.ts(17,5): error TS2322: Type 'A & B' is not assignable to type 'number'.
tests/cases/compiler/errorMessagesIntersectionTypes04.ts(18,5): error TS2322: Type 'A & B' is not assignable to type 'boolean'.
tests/cases/compiler/errorMessagesIntersectionTypes04.ts(19,5): error TS2322: Type 'A & B' is not assignable to type 'string'.
tests/cases/compiler/errorMessagesIntersectionTypes04.ts(21,5): error TS2322: Type 'number & boolean' is not assignable to type 'string'.


==== tests/cases/compiler/errorMessagesIntersectionTypes04.ts (4 errors) ====
interface A {
a;
}

interface B {
b;
}

function f<T, U extends A, V extends U>(): void {
let num: number;
let bool: boolean;
let str: string;

let a_and_b: A & B;
let num_and_bool: number & boolean;

num = a_and_b;
~~~
!!! error TS2322: Type 'A & B' is not assignable to type 'number'.
bool = a_and_b;
~~~~
!!! error TS2322: Type 'A & B' is not assignable to type 'boolean'.
str = a_and_b;
~~~
!!! error TS2322: Type 'A & B' is not assignable to type 'string'.

str = num_and_bool;
~~~
!!! error TS2322: Type 'number & boolean' is not assignable to type 'string'.
}
36 changes: 36 additions & 0 deletions tests/baselines/reference/errorMessagesIntersectionTypes04.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//// [errorMessagesIntersectionTypes04.ts]
interface A {
a;
}

interface B {
b;
}

function f<T, U extends A, V extends U>(): void {
let num: number;
let bool: boolean;
let str: string;

let a_and_b: A & B;
let num_and_bool: number & boolean;

num = a_and_b;
bool = a_and_b;
str = a_and_b;

str = num_and_bool;
}

//// [errorMessagesIntersectionTypes04.js]
function f() {
var num;
var bool;
var str;
var a_and_b;
var num_and_bool;
num = a_and_b;
bool = a_and_b;
str = a_and_b;
str = num_and_bool;
}
Loading