From 00dd1f0609a65b6854b6b68e41c35f315c91f310 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 29 Oct 2019 15:08:59 -0700 Subject: [PATCH] Add isIntersectionConstituent to relation key (#34789) * Add isIntersectionConstituent to relation key isIntersectionConstituent controls whether relation checking performs excess property and common property checks. It is possible to fail a relation check with excess property checks turned on, cache the result, and then skip a relation check with excess property checks that would have succeeded. #33133 provides an example of such a program. Fixes #33133 the right way, so I reverted the fix at #33213 Fixes #34762 (by reverting #33213) Fixes #33944 -- I added the test from #34646 * Update comments in test --- src/compiler/checker.ts | 19 +++--- .../commonTypeIntersection.errors.txt | 26 ++++++++ .../reference/commonTypeIntersection.js | 10 +++ .../reference/commonTypeIntersection.symbols | 21 +++++++ .../reference/commonTypeIntersection.types | 21 +++++++ ...yofReliesOnKeyofNeverUpperBound.errors.txt | 62 ++++++++++--------- .../intersectionAndUnionTypes.errors.txt | 10 +-- ...tersectionMemberOfUnionNarrowsCorrectly.js | 11 ++++ ...ctionMemberOfUnionNarrowsCorrectly.symbols | 27 ++++++++ ...sectionMemberOfUnionNarrowsCorrectly.types | 20 ++++++ ...sertionsWithIntersectionTypes01.errors.txt | 3 + .../unionThisTypeInFunctions.errors.txt | 16 +++-- .../intersection/commonTypeIntersection.ts | 4 ++ ...tersectionMemberOfUnionNarrowsCorrectly.ts | 4 ++ 14 files changed, 209 insertions(+), 45 deletions(-) create mode 100644 tests/baselines/reference/commonTypeIntersection.errors.txt create mode 100644 tests/baselines/reference/commonTypeIntersection.js create mode 100644 tests/baselines/reference/commonTypeIntersection.symbols create mode 100644 tests/baselines/reference/commonTypeIntersection.types create mode 100644 tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.js create mode 100644 tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.symbols create mode 100644 tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.types create mode 100644 tests/cases/conformance/types/intersection/commonTypeIntersection.ts create mode 100644 tests/cases/conformance/types/intersection/intersectionMemberOfUnionNarrowsCorrectly.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3a88ddd3f073e..e278a96a841f7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14165,7 +14165,7 @@ namespace ts { return true; } if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { - const related = relation.get(getRelationKey(source, target, relation)); + const related = relation.get(getRelationKey(source, target, /*isIntersectionConstituent*/ false, relation)); if (related !== undefined) { return !!(related & RelationComparisonResult.Succeeded); } @@ -14571,7 +14571,7 @@ namespace ts { // and we need to handle "each" relations before "some" relations for the same kind of type. if (source.flags & TypeFlags.Union) { result = relation === comparableRelation ? - someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), isIntersectionConstituent) : + someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)) : eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)); } else { @@ -14609,7 +14609,7 @@ namespace ts { // // - For a primitive type or type parameter (such as 'number = A & B') there is no point in // breaking the intersection apart. - result = someTypeRelatedToType(source, target, /*reportErrors*/ false, /*isIntersectionConstituent*/ true); + result = someTypeRelatedToType(source, target, /*reportErrors*/ false); } if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors, isIntersectionConstituent)) { @@ -14903,14 +14903,14 @@ namespace ts { return result; } - function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary { + function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { const sourceTypes = source.types; if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { return Ternary.True; } const len = sourceTypes.length; for (let i = 0; i < len; i++) { - const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1, /*headMessage*/ undefined, isIntersectionConstituent); + const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1); if (related) { return related; } @@ -14997,7 +14997,7 @@ namespace ts { if (overflow) { return Ternary.False; } - const id = getRelationKey(source, target, relation); + const id = getRelationKey(source, target, isIntersectionConstituent, relation); const entry = relation.get(id); if (entry !== undefined) { if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) { @@ -16211,17 +16211,18 @@ namespace ts { * To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters. * For other cases, the types ids are used. */ - function getRelationKey(source: Type, target: Type, relation: Map) { + function getRelationKey(source: Type, target: Type, isIntersectionConstituent: boolean, relation: Map) { if (relation === identityRelation && source.id > target.id) { const temp = source; source = target; target = temp; } + const intersection = isIntersectionConstituent ? "&" : ""; if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) { const typeParameters: Type[] = []; - return getTypeReferenceId(source, typeParameters) + "," + getTypeReferenceId(target, typeParameters); + return getTypeReferenceId(source, typeParameters) + "," + getTypeReferenceId(target, typeParameters) + intersection; } - return source.id + "," + target.id; + return source.id + "," + target.id + intersection; } // Invoke the callback for each underlying property symbol of the given symbol and return the first diff --git a/tests/baselines/reference/commonTypeIntersection.errors.txt b/tests/baselines/reference/commonTypeIntersection.errors.txt new file mode 100644 index 0000000000000..c10f8e2cfeca3 --- /dev/null +++ b/tests/baselines/reference/commonTypeIntersection.errors.txt @@ -0,0 +1,26 @@ +tests/cases/conformance/types/intersection/commonTypeIntersection.ts(2,5): error TS2322: Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; } & { a: boolean; }'. + Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; }'. + Types of property '__typename' are incompatible. + Type '"TypeTwo"' is not assignable to type '"TypeOne"'. +tests/cases/conformance/types/intersection/commonTypeIntersection.ts(4,5): error TS2322: Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; } & string'. + Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; }'. + Types of property '__typename' are incompatible. + Type '"TypeTwo"' is not assignable to type '"TypeOne"'. + + +==== tests/cases/conformance/types/intersection/commonTypeIntersection.ts (2 errors) ==== + declare let x1: { __typename?: 'TypeTwo' } & { a: boolean }; + let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here + ~~ +!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; } & { a: boolean; }'. +!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; }'. +!!! error TS2322: Types of property '__typename' are incompatible. +!!! error TS2322: Type '"TypeTwo"' is not assignable to type '"TypeOne"'. + declare let x2: { __typename?: 'TypeTwo' } & string; + let y2: { __typename?: 'TypeOne' } & string = x2; // should error here + ~~ +!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; } & string'. +!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; }'. +!!! error TS2322: Types of property '__typename' are incompatible. +!!! error TS2322: Type '"TypeTwo"' is not assignable to type '"TypeOne"'. + \ No newline at end of file diff --git a/tests/baselines/reference/commonTypeIntersection.js b/tests/baselines/reference/commonTypeIntersection.js new file mode 100644 index 0000000000000..1bef2b3b06c05 --- /dev/null +++ b/tests/baselines/reference/commonTypeIntersection.js @@ -0,0 +1,10 @@ +//// [commonTypeIntersection.ts] +declare let x1: { __typename?: 'TypeTwo' } & { a: boolean }; +let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here +declare let x2: { __typename?: 'TypeTwo' } & string; +let y2: { __typename?: 'TypeOne' } & string = x2; // should error here + + +//// [commonTypeIntersection.js] +var y1 = x1; // should error here +var y2 = x2; // should error here diff --git a/tests/baselines/reference/commonTypeIntersection.symbols b/tests/baselines/reference/commonTypeIntersection.symbols new file mode 100644 index 0000000000000..3c81f5f450848 --- /dev/null +++ b/tests/baselines/reference/commonTypeIntersection.symbols @@ -0,0 +1,21 @@ +=== tests/cases/conformance/types/intersection/commonTypeIntersection.ts === +declare let x1: { __typename?: 'TypeTwo' } & { a: boolean }; +>x1 : Symbol(x1, Decl(commonTypeIntersection.ts, 0, 11)) +>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 0, 17)) +>a : Symbol(a, Decl(commonTypeIntersection.ts, 0, 46)) + +let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here +>y1 : Symbol(y1, Decl(commonTypeIntersection.ts, 1, 3)) +>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 1, 9)) +>a : Symbol(a, Decl(commonTypeIntersection.ts, 1, 38)) +>x1 : Symbol(x1, Decl(commonTypeIntersection.ts, 0, 11)) + +declare let x2: { __typename?: 'TypeTwo' } & string; +>x2 : Symbol(x2, Decl(commonTypeIntersection.ts, 2, 11)) +>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 2, 17)) + +let y2: { __typename?: 'TypeOne' } & string = x2; // should error here +>y2 : Symbol(y2, Decl(commonTypeIntersection.ts, 3, 3)) +>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 3, 9)) +>x2 : Symbol(x2, Decl(commonTypeIntersection.ts, 2, 11)) + diff --git a/tests/baselines/reference/commonTypeIntersection.types b/tests/baselines/reference/commonTypeIntersection.types new file mode 100644 index 0000000000000..aa14b244bb062 --- /dev/null +++ b/tests/baselines/reference/commonTypeIntersection.types @@ -0,0 +1,21 @@ +=== tests/cases/conformance/types/intersection/commonTypeIntersection.ts === +declare let x1: { __typename?: 'TypeTwo' } & { a: boolean }; +>x1 : { __typename?: "TypeTwo"; } & { a: boolean; } +>__typename : "TypeTwo" +>a : boolean + +let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here +>y1 : { __typename?: "TypeOne"; } & { a: boolean; } +>__typename : "TypeOne" +>a : boolean +>x1 : { __typename?: "TypeTwo"; } & { a: boolean; } + +declare let x2: { __typename?: 'TypeTwo' } & string; +>x2 : { __typename?: "TypeTwo"; } & string +>__typename : "TypeTwo" + +let y2: { __typename?: 'TypeOne' } & string = x2; // should error here +>y2 : { __typename?: "TypeOne"; } & string +>__typename : "TypeOne" +>x2 : { __typename?: "TypeTwo"; } & string + diff --git a/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt b/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt index af63c18523d6a..9abaa6db80393 100644 --- a/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt +++ b/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt @@ -5,20 +5,23 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. Type '"text"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. Type '"text"' is not assignable to type 'ChannelOfType["type"]'. - Type 'T' is not assignable to type 'ChannelOfType["type"]'. - Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. - Type '"text"' is not assignable to type 'ChannelOfType["type"]'. - Type '"text"' is not assignable to type 'T & "text"'. - Type '"text"' is not assignable to type 'T'. - '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. - Type 'T' is not assignable to type 'T & "text"'. - Type '"text" | "email"' is not assignable to type 'T & "text"'. - Type '"text"' is not assignable to type 'T & "text"'. - Type '"text"' is not assignable to type 'T'. - '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. - Type 'T' is not assignable to type '"text"'. - Type '"text" | "email"' is not assignable to type '"text"'. - Type '"email"' is not assignable to type '"text"'. + Type '"text"' is not assignable to type 'T & "text"'. + Type '"text"' is not assignable to type 'T'. + '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. + Type 'T' is not assignable to type 'ChannelOfType["type"]'. + Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. + Type '"text"' is not assignable to type 'ChannelOfType["type"]'. + Type '"text"' is not assignable to type 'T & "text"'. + Type '"text"' is not assignable to type 'T'. + '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. + Type 'T' is not assignable to type 'T & "text"'. + Type '"text" | "email"' is not assignable to type 'T & "text"'. + Type '"text"' is not assignable to type 'T & "text"'. + Type '"text"' is not assignable to type 'T'. + '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. + Type 'T' is not assignable to type '"text"'. + Type '"text" | "email"' is not assignable to type '"text"'. + Type '"email"' is not assignable to type '"text"'. ==== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts (1 errors) ==== @@ -63,20 +66,23 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t !!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. !!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. !!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text"' is not assignable to type 'T'. -!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. -!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text"' is not assignable to type 'T'. -!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. -!!! error TS2322: Type 'T' is not assignable to type '"text"'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'. -!!! error TS2322: Type '"email"' is not assignable to type '"text"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T'. +!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. +!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T'. +!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. +!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T'. +!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. +!!! error TS2322: Type 'T' is not assignable to type '"text"'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'. +!!! error TS2322: Type '"email"' is not assignable to type '"text"'. } const newTextChannel = makeNewChannel('text'); diff --git a/tests/baselines/reference/intersectionAndUnionTypes.errors.txt b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt index 4f3b1db01e305..7de8735f6406c 100644 --- a/tests/baselines/reference/intersectionAndUnionTypes.errors.txt +++ b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt @@ -24,14 +24,14 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(29,1): e Property 'd' is missing in type 'A & B' but required in type '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'. + Property 'd' is missing in type 'A & B' but required in type 'D'. 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 'A & D'. Property 'd' is missing in type 'A' but required in type 'D'. 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'. + Property 'b' is missing in type 'C & D' but required in type '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 & C'. @@ -118,7 +118,8 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): e ~ !!! 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'. +!!! error TS2322: Property 'd' is missing in type 'A & B' but required in type 'D'. +!!! related TS2728 tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts:4:15: 'd' is declared here. y = aob; ~ !!! error TS2322: Type 'A | B' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'. @@ -130,7 +131,8 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): e ~ !!! 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'. +!!! error TS2322: Property 'b' is missing in type 'C & D' but required in type 'B'. +!!! related TS2728 tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts:2:15: 'b' is declared here. y = cod; ~ !!! error TS2322: Type 'C | D' is not assignable to type '(A & C) | (A & D) | (B & C) | (B & D)'. diff --git a/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.js b/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.js new file mode 100644 index 0000000000000..059d182b1b2d1 --- /dev/null +++ b/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.js @@ -0,0 +1,11 @@ +//// [intersectionMemberOfUnionNarrowsCorrectly.ts] +export type U = { kind?: 'A', a: string } | { kind?: 'B' } & { b: string }; +type Ex = T extends U ? T : never; +declare let x: Ex +x.a + + +//// [intersectionMemberOfUnionNarrowsCorrectly.js] +"use strict"; +exports.__esModule = true; +x.a; diff --git a/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.symbols b/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.symbols new file mode 100644 index 0000000000000..d10772a93f56b --- /dev/null +++ b/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/types/intersection/intersectionMemberOfUnionNarrowsCorrectly.ts === +export type U = { kind?: 'A', a: string } | { kind?: 'B' } & { b: string }; +>U : Symbol(U, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 0)) +>kind : Symbol(kind, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 17)) +>a : Symbol(a, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 29)) +>kind : Symbol(kind, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 45)) +>b : Symbol(b, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 62)) + +type Ex = T extends U ? T : never; +>Ex : Symbol(Ex, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 75)) +>T : Symbol(T, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 1, 8)) +>U : Symbol(U, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 1, 10)) +>T : Symbol(T, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 1, 8)) +>U : Symbol(U, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 1, 10)) +>T : Symbol(T, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 1, 8)) + +declare let x: Ex +>x : Symbol(x, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 2, 11)) +>Ex : Symbol(Ex, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 75)) +>U : Symbol(U, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 0)) +>kind : Symbol(kind, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 2, 22)) + +x.a +>x.a : Symbol(a, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 29)) +>x : Symbol(x, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 2, 11)) +>a : Symbol(a, Decl(intersectionMemberOfUnionNarrowsCorrectly.ts, 0, 29)) + diff --git a/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.types b/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.types new file mode 100644 index 0000000000000..77805ece13b11 --- /dev/null +++ b/tests/baselines/reference/intersectionMemberOfUnionNarrowsCorrectly.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/types/intersection/intersectionMemberOfUnionNarrowsCorrectly.ts === +export type U = { kind?: 'A', a: string } | { kind?: 'B' } & { b: string }; +>U : U +>kind : "A" +>a : string +>kind : "B" +>b : string + +type Ex = T extends U ? T : never; +>Ex : Ex + +declare let x: Ex +>x : { kind?: "A"; a: string; } +>kind : "A" + +x.a +>x.a : string +>x : { kind?: "A"; a: string; } +>a : string + diff --git a/tests/baselines/reference/typeAssertionsWithIntersectionTypes01.errors.txt b/tests/baselines/reference/typeAssertionsWithIntersectionTypes01.errors.txt index 29a7f49d2dbe8..d7df5037490ae 100644 --- a/tests/baselines/reference/typeAssertionsWithIntersectionTypes01.errors.txt +++ b/tests/baselines/reference/typeAssertionsWithIntersectionTypes01.errors.txt @@ -1,6 +1,7 @@ tests/cases/conformance/types/typeRelationships/comparable/typeAssertionsWithIntersectionTypes01.ts(17,9): error TS2352: Conversion of type 'I2' to type 'I1 & I3' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property 'p3' is missing in type 'I2' but required in type 'I3'. tests/cases/conformance/types/typeRelationships/comparable/typeAssertionsWithIntersectionTypes01.ts(18,9): error TS2352: Conversion of type 'I2' to type 'I3' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. + Property 'p3' is missing in type 'I2' but required in type 'I3'. ==== tests/cases/conformance/types/typeRelationships/comparable/typeAssertionsWithIntersectionTypes01.ts (2 errors) ==== @@ -28,6 +29,8 @@ tests/cases/conformance/types/typeRelationships/comparable/typeAssertionsWithInt var b = z; ~~~~~ !!! error TS2352: Conversion of type 'I2' to type 'I3' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. +!!! error TS2352: Property 'p3' is missing in type 'I2' but required in type 'I3'. +!!! related TS2728 tests/cases/conformance/types/typeRelationships/comparable/typeAssertionsWithIntersectionTypes01.ts:10:5: 'p3' is declared here. var c = z; var d = y; \ No newline at end of file diff --git a/tests/baselines/reference/unionThisTypeInFunctions.errors.txt b/tests/baselines/reference/unionThisTypeInFunctions.errors.txt index db03a5426fb43..f4f0377a0874c 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.errors.txt +++ b/tests/baselines/reference/unionThisTypeInFunctions.errors.txt @@ -5,8 +5,12 @@ tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts(10,5): error Type '(this: Real, n: number) => void' is not assignable to type '(this: Fake, n: number) => void'. The 'this' types of each signature are incompatible. Type 'Fake' is not assignable to type 'Real'. - Types of property 'data' are incompatible. - Type 'number' is not assignable to type 'string'. + Types of property 'method' are incompatible. + Type '(this: Fake, n: number) => void' is not assignable to type '(this: Real, n: number) => void'. + The 'this' types of each signature are incompatible. + Type 'Real' is not assignable to type 'Fake'. + Types of property 'data' are incompatible. + Type 'string' is not assignable to type 'number'. ==== tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts (1 errors) ==== @@ -28,7 +32,11 @@ tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts(10,5): error !!! error TS2684: Type '(this: Real, n: number) => void' is not assignable to type '(this: Fake, n: number) => void'. !!! error TS2684: The 'this' types of each signature are incompatible. !!! error TS2684: Type 'Fake' is not assignable to type 'Real'. -!!! error TS2684: Types of property 'data' are incompatible. -!!! error TS2684: Type 'number' is not assignable to type 'string'. +!!! error TS2684: Types of property 'method' are incompatible. +!!! error TS2684: Type '(this: Fake, n: number) => void' is not assignable to type '(this: Real, n: number) => void'. +!!! error TS2684: The 'this' types of each signature are incompatible. +!!! error TS2684: Type 'Real' is not assignable to type 'Fake'. +!!! error TS2684: Types of property 'data' are incompatible. +!!! error TS2684: Type 'string' is not assignable to type 'number'. } \ No newline at end of file diff --git a/tests/cases/conformance/types/intersection/commonTypeIntersection.ts b/tests/cases/conformance/types/intersection/commonTypeIntersection.ts new file mode 100644 index 0000000000000..1b4ce3746bcad --- /dev/null +++ b/tests/cases/conformance/types/intersection/commonTypeIntersection.ts @@ -0,0 +1,4 @@ +declare let x1: { __typename?: 'TypeTwo' } & { a: boolean }; +let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here +declare let x2: { __typename?: 'TypeTwo' } & string; +let y2: { __typename?: 'TypeOne' } & string = x2; // should error here diff --git a/tests/cases/conformance/types/intersection/intersectionMemberOfUnionNarrowsCorrectly.ts b/tests/cases/conformance/types/intersection/intersectionMemberOfUnionNarrowsCorrectly.ts new file mode 100644 index 0000000000000..d2657011dae6b --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionMemberOfUnionNarrowsCorrectly.ts @@ -0,0 +1,4 @@ +export type U = { kind?: 'A', a: string } | { kind?: 'B' } & { b: string }; +type Ex = T extends U ? T : never; +declare let x: Ex +x.a