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
This commit is contained in:
Nathan Shively-Sanders
2019-10-28 15:24:34 -07:00
parent 05cbe5ac8e
commit 2e0b4513ef
14 changed files with 209 additions and 45 deletions
+10 -9
View File
@@ -14161,7 +14161,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);
}
@@ -14567,7 +14567,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 {
@@ -14605,7 +14605,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(<IntersectionType>source, target, /*reportErrors*/ false, /*isIntersectionConstituent*/ true);
result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false);
}
if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) {
if (result = recursiveTypeRelatedTo(source, target, reportErrors, isIntersectionConstituent)) {
@@ -14899,14 +14899,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;
}
@@ -14993,7 +14993,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)) {
@@ -16207,17 +16207,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<RelationComparisonResult>) {
function getRelationKey(source: Type, target: Type, isIntersectionConstituent: boolean, relation: Map<RelationComparisonResult>) {
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(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters);
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>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
@@ -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; // No error!
~~
!!! 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; // No error!
~~
!!! 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"'.
@@ -0,0 +1,10 @@
//// [commonTypeIntersection.ts]
declare let x1: { __typename?: 'TypeTwo' } & { a: boolean };
let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // No error!
declare let x2: { __typename?: 'TypeTwo' } & string;
let y2: { __typename?: 'TypeOne' } & string = x2; // No error!
//// [commonTypeIntersection.js]
var y1 = x1; // No error!
var y2 = x2; // No error!
@@ -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; // No error!
>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; // No error!
>y2 : Symbol(y2, Decl(commonTypeIntersection.ts, 3, 3))
>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 3, 9))
>x2 : Symbol(x2, Decl(commonTypeIntersection.ts, 2, 11))
@@ -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; // No error!
>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; // No error!
>y2 : { __typename?: "TypeOne"; } & string
>__typename : "TypeOne"
>x2 : { __typename?: "TypeTwo"; } & string
@@ -5,20 +5,23 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["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<T, TextChannel>["type"]'.
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["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<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["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<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["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');
@@ -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)'.
@@ -0,0 +1,11 @@
//// [intersectionMemberOfUnionNarrowsCorrectly.ts]
export type U = { kind?: 'A', a: string } | { kind?: 'B' } & { b: string };
type Ex<T, U> = T extends U ? T : never;
declare let x: Ex<U, { kind?: 'A' }>
x.a
//// [intersectionMemberOfUnionNarrowsCorrectly.js]
"use strict";
exports.__esModule = true;
x.a;
@@ -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, U> = 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<U, { kind?: 'A' }>
>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))
@@ -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, U> = T extends U ? T : never;
>Ex : Ex<T, U>
declare let x: Ex<U, { kind?: 'A' }>
>x : { kind?: "A"; a: string; }
>kind : "A"
x.a
>x.a : string
>x : { kind?: "A"; a: string; }
>a : string
@@ -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 = <I3>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 = <I2>z;
var d = <I1>y;
@@ -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'.
}
@@ -0,0 +1,4 @@
declare let x1: { __typename?: 'TypeTwo' } & { a: boolean };
let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // No error!
declare let x2: { __typename?: 'TypeTwo' } & string;
let y2: { __typename?: 'TypeOne' } & string = x2; // No error!
@@ -0,0 +1,4 @@
export type U = { kind?: 'A', a: string } | { kind?: 'B' } & { b: string };
type Ex<T, U> = T extends U ? T : never;
declare let x: Ex<U, { kind?: 'A' }>
x.a