Merge pull request #11717 from Microsoft/normalizeIntersectionTypes

Normalize union/intersection type combinations
This commit is contained in:
Anders Hejlsberg 2016-10-19 13:15:10 -07:00 committed by GitHub
commit 66857b5f8e
10 changed files with 722 additions and 75 deletions

View File

@ -5604,6 +5604,11 @@ namespace ts {
}
}
// We normalize combinations of intersection and union types based on the distributive property of the '&'
// operator. Specifically, because X & (A | B) is equivalent to X & A | X & B, we can transform intersection
// types with union type constituents into equivalent union types with intersection type constituents and
// effectively ensure that union types are always at the top level in type representations.
//
// We do not perform structural deduplication on intersection types. Intersection types are created only by the &
// type operator and we can't reduce those because we want to support recursive intersection types. For example,
// a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration.
@ -5613,6 +5618,15 @@ namespace ts {
if (types.length === 0) {
return emptyObjectType;
}
for (let i = 0; i < types.length; i++) {
const type = types[i];
if (type.flags & TypeFlags.Union) {
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
return getUnionType(map((<UnionType>type).types, t => getIntersectionType(replaceElement(types, i, t))),
/*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments);
}
}
const typeSet = [] as TypeSet;
addTypesToIntersection(typeSet, types);
if (typeSet.containsAny) {
@ -6560,7 +6574,9 @@ namespace ts {
const saveErrorInfo = errorInfo;
// Note that these checks are specifically ordered to produce correct results.
// Note that these checks are specifically ordered to produce correct results. In particular,
// we need to deconstruct unions before intersections (because unions are always at the top),
// and we need to handle "each" relations before "some" relations for the same kind of type.
if (source.flags & TypeFlags.Union) {
if (relation === comparableRelation) {
result = someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
@ -6568,44 +6584,36 @@ namespace ts {
else {
result = eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
}
if (result) {
return result;
}
}
else if (target.flags & TypeFlags.Union) {
if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive))) {
return result;
}
}
else if (target.flags & TypeFlags.Intersection) {
result = typeRelatedToEachType(source, target as IntersectionType, reportErrors);
if (result) {
if (result = typeRelatedToEachType(source, target as IntersectionType, reportErrors)) {
return result;
}
}
else {
// It is necessary to try these "some" checks on both sides because there may be nested "each" checks
// 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) {
// 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;
}
}
if (target.flags & TypeFlags.Union) {
if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive))) {
return result;
}
else if (source.flags & TypeFlags.Intersection) {
// 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;
}
}

View File

@ -532,6 +532,12 @@ namespace ts {
: undefined;
}
export function replaceElement<T>(array: T[], index: number, value: T): T[] {
const result = array.slice(0);
result[index] = value;
return result;
}
/**
* Performs a binary search, finding the index at which 'value' occurs in 'array'.
* If no such index is found, returns the 2's-complement of first index at which

View File

@ -1,7 +1,8 @@
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(21,5): error TS2322: Type '(number & true) | (number & false)' is not assignable to type 'string'.
Type 'number & true' is not assignable to type 'string'.
==== tests/cases/compiler/errorMessagesIntersectionTypes04.ts (4 errors) ====
@ -33,5 +34,6 @@ tests/cases/compiler/errorMessagesIntersectionTypes04.ts(21,5): error TS2322: Ty
str = num_and_bool;
~~~
!!! error TS2322: Type 'number & boolean' is not assignable to type 'string'.
!!! error TS2322: Type '(number & true) | (number & false)' is not assignable to type 'string'.
!!! error TS2322: Type 'number & true' is not assignable to type 'string'.
}

View File

@ -30,28 +30,29 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(29,1): e
Type 'A & B' is not assignable to type 'C | D'.
Type 'A & B' is not assignable to type 'D'.
Property 'd' is missing in type 'A & B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(31,1): error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'.
Type 'A & B' is not assignable to type 'C | D'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(31,1): error TS2322: Type 'A & B' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
Type 'A & B' is not assignable to type 'B & D'.
Type 'A & B' is not assignable to type 'D'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(32,1): error TS2322: Type 'A | B' is not assignable to type '(A | B) & (C | D)'.
Type 'A' is not assignable to type '(A | B) & (C | D)'.
Type 'A' is not assignable to type 'C | D'.
Type 'A' is not assignable to type 'D'.
Property 'd' is missing in type 'A'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(33,1): error TS2322: Type 'C & D' is not assignable to type '(A | B) & (C | D)'.
Type 'C & D' is not assignable to type 'A | B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(32,1): error TS2322: Type 'A | B' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
Type 'A' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
Type 'A' is not assignable to type 'B & D'.
Type 'A' is not assignable to type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(33,1): error TS2322: Type 'C & D' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
Type 'C & D' is not assignable to type 'B & D'.
Type 'C & D' is not assignable to type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(34,1): error TS2322: Type 'C | D' is not assignable to type '(A | B) & (C | D)'.
Type 'C' is not assignable to type '(A | B) & (C | D)'.
Type 'C' is not assignable to type 'A | B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(34,1): error TS2322: Type 'C | D' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
Type 'C' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
Type 'C' is not assignable to type 'B & D'.
Type 'C' is not assignable to type 'B'.
Property 'b' is missing in type 'C'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(35,1): error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A & B'.
Type '(A | B) & (C | D)' is not assignable to type 'A'.
Property 'a' is missing in type '(A | B) & (C | D)'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C & D'.
Type '(A | B) & (C | D)' is not assignable to type 'C'.
Property 'c' is missing in type '(A | B) & (C | D)'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(35,1): error TS2322: Type '(A & C) | (A & D) | (B & C) | (B & D)' is not assignable to type 'A & B'.
Type 'A & C' is not assignable to type 'A & B'.
Type 'A & C' is not assignable to type 'B'.
Property 'b' is missing in type 'A & C'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): error TS2322: Type '(A & C) | (A & D) | (B & C) | (B & D)' is not assignable to type 'C & D'.
Type 'A & C' is not assignable to type 'C & D'.
Type 'A & C' is not assignable to type 'D'.
Property 'd' is missing in type 'A & C'.
==== tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts (14 errors) ====
@ -127,38 +128,39 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): e
y = anb;
~
!!! error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'A & B' is not assignable to type 'C | D'.
!!! error TS2322: Type 'A & B' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
!!! error TS2322: Type 'A & B' is not assignable to type 'B & D'.
!!! error TS2322: Type 'A & B' is not assignable to type 'D'.
y = aob;
~
!!! error TS2322: Type 'A | B' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'A' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'A' is not assignable to type 'C | D'.
!!! error TS2322: Type 'A' is not assignable to type 'D'.
!!! error TS2322: Property 'd' is missing in type 'A'.
!!! error TS2322: Type 'A | B' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
!!! error TS2322: Type 'A' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
!!! error TS2322: Type 'A' is not assignable to type 'B & D'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
y = cnd;
~
!!! error TS2322: Type 'C & D' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'C & D' is not assignable to type 'A | B'.
!!! error TS2322: Type 'C & D' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
!!! error TS2322: Type 'C & D' is not assignable to type 'B & D'.
!!! error TS2322: Type 'C & D' is not assignable to type 'B'.
y = cod;
~
!!! error TS2322: Type 'C | D' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'C' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'C' is not assignable to type 'A | B'.
!!! error TS2322: Type 'C | D' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
!!! error TS2322: Type 'C' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'.
!!! error TS2322: Type 'C' is not assignable to type 'B & D'.
!!! error TS2322: Type 'C' is not assignable to type 'B'.
!!! error TS2322: Property 'b' is missing in type 'C'.
anb = y;
~~~
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A & B'.
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A'.
!!! error TS2322: Property 'a' is missing in type '(A | B) & (C | D)'.
!!! error TS2322: Type '(A & C) | (A & D) | (B & C) | (B & D)' is not assignable to type 'A & B'.
!!! error TS2322: Type 'A & C' is not assignable to type 'A & B'.
!!! error TS2322: Type 'A & C' is not assignable to type 'B'.
!!! error TS2322: Property 'b' is missing in type 'A & C'.
aob = y; // Ok
cnd = y;
~~~
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C & D'.
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C'.
!!! error TS2322: Property 'c' is missing in type '(A | B) & (C | D)'.
!!! error TS2322: Type '(A & C) | (A & D) | (B & C) | (B & D)' is not assignable to type 'C & D'.
!!! error TS2322: Type 'A & C' is not assignable to type 'C & D'.
!!! error TS2322: Type 'A & C' is not assignable to type 'D'.
!!! error TS2322: Property 'd' is missing in type 'A & C'.
cod = y; // Ok

View File

@ -0,0 +1,79 @@
//// [intersectionTypeNormalization.ts]
interface A { a: string }
interface B { b: string }
interface C { c: string }
interface D { d: string }
// Identical ways of writing the same type
type X1 = (A | B) & (C | D);
type X2 = A & (C | D) | B & (C | D)
type X3 = A & C | A & D | B & C | B & D;
var x: X1;
var x: X2;
var x: X3;
interface X { x: string }
interface Y { y: string }
// Identical ways of writing the same type
type Y1 = (A | X & Y) & (C | D);
type Y2 = A & (C | D) | X & Y & (C | D)
type Y3 = A & C | A & D | X & Y & C | X & Y & D;
var y: Y1;
var y: Y2;
var y: Y3;
interface M { m: string }
interface N { n: string }
// Identical ways of writing the same type
type Z1 = (A | X & (M | N)) & (C | D);
type Z2 = A & (C | D) | X & (M | N) & (C | D)
type Z3 = A & C | A & D | X & (M | N) & C | X & (M | N) & D;
type Z4 = A & C | A & D | X & M & C | X & N & C | X & M & D | X & N & D;
var z: Z1;
var z: Z2;
var z: Z3;
var z: Z4;
// Repro from #9919
type ToString = {
toString(): string;
}
type BoxedValue = { kind: 'int', num: number }
| { kind: 'string', str: string }
type IntersectionFail = BoxedValue & ToString
type IntersectionInline = { kind: 'int', num: number } & ToString
| { kind: 'string', str: string } & ToString
function getValueAsString(value: IntersectionFail): string {
if (value.kind === 'int') {
return '' + value.num;
}
return value.str;
}
//// [intersectionTypeNormalization.js]
var x;
var x;
var x;
var y;
var y;
var y;
var z;
var z;
var z;
var z;
function getValueAsString(value) {
if (value.kind === 'int') {
return '' + value.num;
}
return value.str;
}

View File

@ -0,0 +1,242 @@
=== tests/cases/compiler/intersectionTypeNormalization.ts ===
interface A { a: string }
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>a : Symbol(A.a, Decl(intersectionTypeNormalization.ts, 0, 13))
interface B { b: string }
>B : Symbol(B, Decl(intersectionTypeNormalization.ts, 0, 25))
>b : Symbol(B.b, Decl(intersectionTypeNormalization.ts, 1, 13))
interface C { c: string }
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>c : Symbol(C.c, Decl(intersectionTypeNormalization.ts, 2, 13))
interface D { d: string }
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>d : Symbol(D.d, Decl(intersectionTypeNormalization.ts, 3, 13))
// Identical ways of writing the same type
type X1 = (A | B) & (C | D);
>X1 : Symbol(X1, Decl(intersectionTypeNormalization.ts, 3, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeNormalization.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type X2 = A & (C | D) | B & (C | D)
>X2 : Symbol(X2, Decl(intersectionTypeNormalization.ts, 6, 28))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>B : Symbol(B, Decl(intersectionTypeNormalization.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type X3 = A & C | A & D | B & C | B & D;
>X3 : Symbol(X3, Decl(intersectionTypeNormalization.ts, 7, 35))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>B : Symbol(B, Decl(intersectionTypeNormalization.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>B : Symbol(B, Decl(intersectionTypeNormalization.ts, 0, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
var x: X1;
>x : Symbol(x, Decl(intersectionTypeNormalization.ts, 10, 3), Decl(intersectionTypeNormalization.ts, 11, 3), Decl(intersectionTypeNormalization.ts, 12, 3))
>X1 : Symbol(X1, Decl(intersectionTypeNormalization.ts, 3, 25))
var x: X2;
>x : Symbol(x, Decl(intersectionTypeNormalization.ts, 10, 3), Decl(intersectionTypeNormalization.ts, 11, 3), Decl(intersectionTypeNormalization.ts, 12, 3))
>X2 : Symbol(X2, Decl(intersectionTypeNormalization.ts, 6, 28))
var x: X3;
>x : Symbol(x, Decl(intersectionTypeNormalization.ts, 10, 3), Decl(intersectionTypeNormalization.ts, 11, 3), Decl(intersectionTypeNormalization.ts, 12, 3))
>X3 : Symbol(X3, Decl(intersectionTypeNormalization.ts, 7, 35))
interface X { x: string }
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>x : Symbol(X.x, Decl(intersectionTypeNormalization.ts, 14, 13))
interface Y { y: string }
>Y : Symbol(Y, Decl(intersectionTypeNormalization.ts, 14, 25))
>y : Symbol(Y.y, Decl(intersectionTypeNormalization.ts, 15, 13))
// Identical ways of writing the same type
type Y1 = (A | X & Y) & (C | D);
>Y1 : Symbol(Y1, Decl(intersectionTypeNormalization.ts, 15, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>Y : Symbol(Y, Decl(intersectionTypeNormalization.ts, 14, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type Y2 = A & (C | D) | X & Y & (C | D)
>Y2 : Symbol(Y2, Decl(intersectionTypeNormalization.ts, 18, 32))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>Y : Symbol(Y, Decl(intersectionTypeNormalization.ts, 14, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type Y3 = A & C | A & D | X & Y & C | X & Y & D;
>Y3 : Symbol(Y3, Decl(intersectionTypeNormalization.ts, 19, 39))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>Y : Symbol(Y, Decl(intersectionTypeNormalization.ts, 14, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>Y : Symbol(Y, Decl(intersectionTypeNormalization.ts, 14, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
var y: Y1;
>y : Symbol(y, Decl(intersectionTypeNormalization.ts, 22, 3), Decl(intersectionTypeNormalization.ts, 23, 3), Decl(intersectionTypeNormalization.ts, 24, 3))
>Y1 : Symbol(Y1, Decl(intersectionTypeNormalization.ts, 15, 25))
var y: Y2;
>y : Symbol(y, Decl(intersectionTypeNormalization.ts, 22, 3), Decl(intersectionTypeNormalization.ts, 23, 3), Decl(intersectionTypeNormalization.ts, 24, 3))
>Y2 : Symbol(Y2, Decl(intersectionTypeNormalization.ts, 18, 32))
var y: Y3;
>y : Symbol(y, Decl(intersectionTypeNormalization.ts, 22, 3), Decl(intersectionTypeNormalization.ts, 23, 3), Decl(intersectionTypeNormalization.ts, 24, 3))
>Y3 : Symbol(Y3, Decl(intersectionTypeNormalization.ts, 19, 39))
interface M { m: string }
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>m : Symbol(M.m, Decl(intersectionTypeNormalization.ts, 26, 13))
interface N { n: string }
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>n : Symbol(N.n, Decl(intersectionTypeNormalization.ts, 27, 13))
// Identical ways of writing the same type
type Z1 = (A | X & (M | N)) & (C | D);
>Z1 : Symbol(Z1, Decl(intersectionTypeNormalization.ts, 27, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type Z2 = A & (C | D) | X & (M | N) & (C | D)
>Z2 : Symbol(Z2, Decl(intersectionTypeNormalization.ts, 30, 38))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type Z3 = A & C | A & D | X & (M | N) & C | X & (M | N) & D;
>Z3 : Symbol(Z3, Decl(intersectionTypeNormalization.ts, 31, 45))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
type Z4 = A & C | A & D | X & M & C | X & N & C | X & M & D | X & N & D;
>Z4 : Symbol(Z4, Decl(intersectionTypeNormalization.ts, 32, 60))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>A : Symbol(A, Decl(intersectionTypeNormalization.ts, 0, 0))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>C : Symbol(C, Decl(intersectionTypeNormalization.ts, 1, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>M : Symbol(M, Decl(intersectionTypeNormalization.ts, 24, 10))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
>X : Symbol(X, Decl(intersectionTypeNormalization.ts, 12, 10))
>N : Symbol(N, Decl(intersectionTypeNormalization.ts, 26, 25))
>D : Symbol(D, Decl(intersectionTypeNormalization.ts, 2, 25))
var z: Z1;
>z : Symbol(z, Decl(intersectionTypeNormalization.ts, 35, 3), Decl(intersectionTypeNormalization.ts, 36, 3), Decl(intersectionTypeNormalization.ts, 37, 3), Decl(intersectionTypeNormalization.ts, 38, 3))
>Z1 : Symbol(Z1, Decl(intersectionTypeNormalization.ts, 27, 25))
var z: Z2;
>z : Symbol(z, Decl(intersectionTypeNormalization.ts, 35, 3), Decl(intersectionTypeNormalization.ts, 36, 3), Decl(intersectionTypeNormalization.ts, 37, 3), Decl(intersectionTypeNormalization.ts, 38, 3))
>Z2 : Symbol(Z2, Decl(intersectionTypeNormalization.ts, 30, 38))
var z: Z3;
>z : Symbol(z, Decl(intersectionTypeNormalization.ts, 35, 3), Decl(intersectionTypeNormalization.ts, 36, 3), Decl(intersectionTypeNormalization.ts, 37, 3), Decl(intersectionTypeNormalization.ts, 38, 3))
>Z3 : Symbol(Z3, Decl(intersectionTypeNormalization.ts, 31, 45))
var z: Z4;
>z : Symbol(z, Decl(intersectionTypeNormalization.ts, 35, 3), Decl(intersectionTypeNormalization.ts, 36, 3), Decl(intersectionTypeNormalization.ts, 37, 3), Decl(intersectionTypeNormalization.ts, 38, 3))
>Z4 : Symbol(Z4, Decl(intersectionTypeNormalization.ts, 32, 60))
// Repro from #9919
type ToString = {
>ToString : Symbol(ToString, Decl(intersectionTypeNormalization.ts, 38, 10))
toString(): string;
>toString : Symbol(toString, Decl(intersectionTypeNormalization.ts, 42, 17))
}
type BoxedValue = { kind: 'int', num: number }
>BoxedValue : Symbol(BoxedValue, Decl(intersectionTypeNormalization.ts, 44, 1))
>kind : Symbol(kind, Decl(intersectionTypeNormalization.ts, 46, 19))
>num : Symbol(num, Decl(intersectionTypeNormalization.ts, 46, 32))
| { kind: 'string', str: string }
>kind : Symbol(kind, Decl(intersectionTypeNormalization.ts, 47, 19))
>str : Symbol(str, Decl(intersectionTypeNormalization.ts, 47, 35))
type IntersectionFail = BoxedValue & ToString
>IntersectionFail : Symbol(IntersectionFail, Decl(intersectionTypeNormalization.ts, 47, 49))
>BoxedValue : Symbol(BoxedValue, Decl(intersectionTypeNormalization.ts, 44, 1))
>ToString : Symbol(ToString, Decl(intersectionTypeNormalization.ts, 38, 10))
type IntersectionInline = { kind: 'int', num: number } & ToString
>IntersectionInline : Symbol(IntersectionInline, Decl(intersectionTypeNormalization.ts, 49, 45))
>kind : Symbol(kind, Decl(intersectionTypeNormalization.ts, 51, 27))
>num : Symbol(num, Decl(intersectionTypeNormalization.ts, 51, 40))
>ToString : Symbol(ToString, Decl(intersectionTypeNormalization.ts, 38, 10))
| { kind: 'string', str: string } & ToString
>kind : Symbol(kind, Decl(intersectionTypeNormalization.ts, 52, 27))
>str : Symbol(str, Decl(intersectionTypeNormalization.ts, 52, 43))
>ToString : Symbol(ToString, Decl(intersectionTypeNormalization.ts, 38, 10))
function getValueAsString(value: IntersectionFail): string {
>getValueAsString : Symbol(getValueAsString, Decl(intersectionTypeNormalization.ts, 52, 68))
>value : Symbol(value, Decl(intersectionTypeNormalization.ts, 54, 26))
>IntersectionFail : Symbol(IntersectionFail, Decl(intersectionTypeNormalization.ts, 47, 49))
if (value.kind === 'int') {
>value.kind : Symbol(kind, Decl(intersectionTypeNormalization.ts, 46, 19), Decl(intersectionTypeNormalization.ts, 47, 19))
>value : Symbol(value, Decl(intersectionTypeNormalization.ts, 54, 26))
>kind : Symbol(kind, Decl(intersectionTypeNormalization.ts, 46, 19), Decl(intersectionTypeNormalization.ts, 47, 19))
return '' + value.num;
>value.num : Symbol(num, Decl(intersectionTypeNormalization.ts, 46, 32))
>value : Symbol(value, Decl(intersectionTypeNormalization.ts, 54, 26))
>num : Symbol(num, Decl(intersectionTypeNormalization.ts, 46, 32))
}
return value.str;
>value.str : Symbol(str, Decl(intersectionTypeNormalization.ts, 47, 35))
>value : Symbol(value, Decl(intersectionTypeNormalization.ts, 54, 26))
>str : Symbol(str, Decl(intersectionTypeNormalization.ts, 47, 35))
}

View File

@ -0,0 +1,246 @@
=== tests/cases/compiler/intersectionTypeNormalization.ts ===
interface A { a: string }
>A : A
>a : string
interface B { b: string }
>B : B
>b : string
interface C { c: string }
>C : C
>c : string
interface D { d: string }
>D : D
>d : string
// Identical ways of writing the same type
type X1 = (A | B) & (C | D);
>X1 : X1
>A : A
>B : B
>C : C
>D : D
type X2 = A & (C | D) | B & (C | D)
>X2 : X1
>A : A
>C : C
>D : D
>B : B
>C : C
>D : D
type X3 = A & C | A & D | B & C | B & D;
>X3 : X1
>A : A
>C : C
>A : A
>D : D
>B : B
>C : C
>B : B
>D : D
var x: X1;
>x : X1
>X1 : X1
var x: X2;
>x : X1
>X2 : X1
var x: X3;
>x : X1
>X3 : X1
interface X { x: string }
>X : X
>x : string
interface Y { y: string }
>Y : Y
>y : string
// Identical ways of writing the same type
type Y1 = (A | X & Y) & (C | D);
>Y1 : Y1
>A : A
>X : X
>Y : Y
>C : C
>D : D
type Y2 = A & (C | D) | X & Y & (C | D)
>Y2 : Y1
>A : A
>C : C
>D : D
>X : X
>Y : Y
>C : C
>D : D
type Y3 = A & C | A & D | X & Y & C | X & Y & D;
>Y3 : Y1
>A : A
>C : C
>A : A
>D : D
>X : X
>Y : Y
>C : C
>X : X
>Y : Y
>D : D
var y: Y1;
>y : Y1
>Y1 : Y1
var y: Y2;
>y : Y1
>Y2 : Y1
var y: Y3;
>y : Y1
>Y3 : Y1
interface M { m: string }
>M : M
>m : string
interface N { n: string }
>N : N
>n : string
// Identical ways of writing the same type
type Z1 = (A | X & (M | N)) & (C | D);
>Z1 : Z1
>A : A
>X : X
>M : M
>N : N
>C : C
>D : D
type Z2 = A & (C | D) | X & (M | N) & (C | D)
>Z2 : Z1
>A : A
>C : C
>D : D
>X : X
>M : M
>N : N
>C : C
>D : D
type Z3 = A & C | A & D | X & (M | N) & C | X & (M | N) & D;
>Z3 : Z1
>A : A
>C : C
>A : A
>D : D
>X : X
>M : M
>N : N
>C : C
>X : X
>M : M
>N : N
>D : D
type Z4 = A & C | A & D | X & M & C | X & N & C | X & M & D | X & N & D;
>Z4 : Z1
>A : A
>C : C
>A : A
>D : D
>X : X
>M : M
>C : C
>X : X
>N : N
>C : C
>X : X
>M : M
>D : D
>X : X
>N : N
>D : D
var z: Z1;
>z : Z1
>Z1 : Z1
var z: Z2;
>z : Z1
>Z2 : Z1
var z: Z3;
>z : Z1
>Z3 : Z1
var z: Z4;
>z : Z1
>Z4 : Z1
// Repro from #9919
type ToString = {
>ToString : { toString(): string; }
toString(): string;
>toString : () => string
}
type BoxedValue = { kind: 'int', num: number }
>BoxedValue : BoxedValue
>kind : "int"
>num : number
| { kind: 'string', str: string }
>kind : "string"
>str : string
type IntersectionFail = BoxedValue & ToString
>IntersectionFail : IntersectionFail
>BoxedValue : BoxedValue
>ToString : { toString(): string; }
type IntersectionInline = { kind: 'int', num: number } & ToString
>IntersectionInline : IntersectionInline
>kind : "int"
>num : number
>ToString : { toString(): string; }
| { kind: 'string', str: string } & ToString
>kind : "string"
>str : string
>ToString : { toString(): string; }
function getValueAsString(value: IntersectionFail): string {
>getValueAsString : (value: IntersectionFail) => string
>value : IntersectionFail
>IntersectionFail : IntersectionFail
if (value.kind === 'int') {
>value.kind === 'int' : boolean
>value.kind : "int" | "string"
>value : IntersectionFail
>kind : "int" | "string"
>'int' : "int"
return '' + value.num;
>'' + value.num : string
>'' : ""
>value.num : number
>value : { kind: "int"; num: number; } & { toString(): string; }
>num : number
}
return value.str;
>value.str : string
>value : { kind: "string"; str: string; } & { toString(): string; }
>str : string
}

View File

@ -1,5 +1,6 @@
tests/cases/conformance/types/typeRelationships/comparable/switchCaseWithIntersectionTypes01.ts(19,10): error TS2678: Type 'number & boolean' is not comparable to type 'string & number'.
Type 'number & boolean' is not comparable to type 'string'.
tests/cases/conformance/types/typeRelationships/comparable/switchCaseWithIntersectionTypes01.ts(19,10): error TS2678: Type '(number & true) | (number & false)' is not comparable to type 'string & number'.
Type 'number & false' is not comparable to type 'string & number'.
Type 'number & false' is not comparable to type 'string'.
tests/cases/conformance/types/typeRelationships/comparable/switchCaseWithIntersectionTypes01.ts(23,10): error TS2678: Type 'boolean' is not comparable to type 'string & number'.
@ -24,8 +25,9 @@ tests/cases/conformance/types/typeRelationships/comparable/switchCaseWithInterse
// Overlap in constituents
case numAndBool:
~~~~~~~~~~
!!! error TS2678: Type 'number & boolean' is not comparable to type 'string & number'.
!!! error TS2678: Type 'number & boolean' is not comparable to type 'string'.
!!! error TS2678: Type '(number & true) | (number & false)' is not comparable to type 'string & number'.
!!! error TS2678: Type 'number & false' is not comparable to type 'string & number'.
!!! error TS2678: Type 'number & false' is not comparable to type 'string'.
break;
// No relation

View File

@ -25,7 +25,7 @@ if (!(result instanceof RegExp)) {
} else if (!result.global) {
>!result.global : boolean
>result.global : string & boolean
>result.global : (string & true) | (string & false)
>result : I & RegExp
>global : string & boolean
>global : (string & true) | (string & false)
}

View File

@ -0,0 +1,60 @@
interface A { a: string }
interface B { b: string }
interface C { c: string }
interface D { d: string }
// Identical ways of writing the same type
type X1 = (A | B) & (C | D);
type X2 = A & (C | D) | B & (C | D)
type X3 = A & C | A & D | B & C | B & D;
var x: X1;
var x: X2;
var x: X3;
interface X { x: string }
interface Y { y: string }
// Identical ways of writing the same type
type Y1 = (A | X & Y) & (C | D);
type Y2 = A & (C | D) | X & Y & (C | D)
type Y3 = A & C | A & D | X & Y & C | X & Y & D;
var y: Y1;
var y: Y2;
var y: Y3;
interface M { m: string }
interface N { n: string }
// Identical ways of writing the same type
type Z1 = (A | X & (M | N)) & (C | D);
type Z2 = A & (C | D) | X & (M | N) & (C | D)
type Z3 = A & C | A & D | X & (M | N) & C | X & (M | N) & D;
type Z4 = A & C | A & D | X & M & C | X & N & C | X & M & D | X & N & D;
var z: Z1;
var z: Z2;
var z: Z3;
var z: Z4;
// Repro from #9919
type ToString = {
toString(): string;
}
type BoxedValue = { kind: 'int', num: number }
| { kind: 'string', str: string }
type IntersectionFail = BoxedValue & ToString
type IntersectionInline = { kind: 'int', num: number } & ToString
| { kind: 'string', str: string } & ToString
function getValueAsString(value: IntersectionFail): string {
if (value.kind === 'int') {
return '' + value.num;
}
return value.str;
}