diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0509d53c9b..50cbb6cb06 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11178,7 +11178,7 @@ namespace ts { } if (relation !== comparableRelation && - !(source.flags & TypeFlags.UnionOrIntersection) && + !(source.flags & TypeFlags.Union) && !(target.flags & TypeFlags.Union) && !isIntersectionConstituent && source !== globalObjectType && diff --git a/tests/baselines/reference/intersectionAsWeakTypeSource.errors.txt b/tests/baselines/reference/intersectionAsWeakTypeSource.errors.txt new file mode 100644 index 0000000000..69da07115a --- /dev/null +++ b/tests/baselines/reference/intersectionAsWeakTypeSource.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts(8,7): error TS2559: Type 'XY' has no properties in common with type 'Z'. +tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts(18,7): error TS2322: Type 'Brand<{ view: number; styleMedia: string; }>' is not assignable to type 'ViewStyle'. + Property 'view' is missing in type 'Number & { __brand: { view: number; styleMedia: string; }; }'. + + +==== tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts (2 errors) ==== + interface X { x: string } + interface Y { y: number } + interface Z { z?: boolean } + + type XY = X & Y; + const xy: XY = {x: 'x', y: 10}; + + const z1: Z = xy; // error, {xy} doesn't overlap with {z} + ~~ +!!! error TS2559: Type 'XY' has no properties in common with type 'Z'. + + + interface ViewStyle { + view: number + styleMedia: string + } + type Brand = number & { __brand: T } + declare function create(styles: T): { [P in keyof T]: Brand }; + const wrapped = create({ first: { view: 0, styleMedia: "???" } }); + const vs: ViewStyle = wrapped.first // error, first is a branded number + ~~ +!!! error TS2322: Type 'Brand<{ view: number; styleMedia: string; }>' is not assignable to type 'ViewStyle'. +!!! error TS2322: Property 'view' is missing in type 'Number & { __brand: { view: number; styleMedia: string; }; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionAsWeakTypeSource.js b/tests/baselines/reference/intersectionAsWeakTypeSource.js new file mode 100644 index 0000000000..fefb6f79c2 --- /dev/null +++ b/tests/baselines/reference/intersectionAsWeakTypeSource.js @@ -0,0 +1,26 @@ +//// [intersectionAsWeakTypeSource.ts] +interface X { x: string } +interface Y { y: number } +interface Z { z?: boolean } + +type XY = X & Y; +const xy: XY = {x: 'x', y: 10}; + +const z1: Z = xy; // error, {xy} doesn't overlap with {z} + + +interface ViewStyle { + view: number + styleMedia: string +} +type Brand = number & { __brand: T } +declare function create(styles: T): { [P in keyof T]: Brand }; +const wrapped = create({ first: { view: 0, styleMedia: "???" } }); +const vs: ViewStyle = wrapped.first // error, first is a branded number + + +//// [intersectionAsWeakTypeSource.js] +var xy = { x: 'x', y: 10 }; +var z1 = xy; // error, {xy} doesn't overlap with {z} +var wrapped = create({ first: { view: 0, styleMedia: "???" } }); +var vs = wrapped.first; // error, first is a branded number diff --git a/tests/baselines/reference/intersectionAsWeakTypeSource.symbols b/tests/baselines/reference/intersectionAsWeakTypeSource.symbols new file mode 100644 index 0000000000..78c35abc28 --- /dev/null +++ b/tests/baselines/reference/intersectionAsWeakTypeSource.symbols @@ -0,0 +1,72 @@ +=== tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts === +interface X { x: string } +>X : Symbol(X, Decl(intersectionAsWeakTypeSource.ts, 0, 0)) +>x : Symbol(X.x, Decl(intersectionAsWeakTypeSource.ts, 0, 13)) + +interface Y { y: number } +>Y : Symbol(Y, Decl(intersectionAsWeakTypeSource.ts, 0, 25)) +>y : Symbol(Y.y, Decl(intersectionAsWeakTypeSource.ts, 1, 13)) + +interface Z { z?: boolean } +>Z : Symbol(Z, Decl(intersectionAsWeakTypeSource.ts, 1, 25)) +>z : Symbol(Z.z, Decl(intersectionAsWeakTypeSource.ts, 2, 13)) + +type XY = X & Y; +>XY : Symbol(XY, Decl(intersectionAsWeakTypeSource.ts, 2, 27)) +>X : Symbol(X, Decl(intersectionAsWeakTypeSource.ts, 0, 0)) +>Y : Symbol(Y, Decl(intersectionAsWeakTypeSource.ts, 0, 25)) + +const xy: XY = {x: 'x', y: 10}; +>xy : Symbol(xy, Decl(intersectionAsWeakTypeSource.ts, 5, 5)) +>XY : Symbol(XY, Decl(intersectionAsWeakTypeSource.ts, 2, 27)) +>x : Symbol(x, Decl(intersectionAsWeakTypeSource.ts, 5, 16)) +>y : Symbol(y, Decl(intersectionAsWeakTypeSource.ts, 5, 23)) + +const z1: Z = xy; // error, {xy} doesn't overlap with {z} +>z1 : Symbol(z1, Decl(intersectionAsWeakTypeSource.ts, 7, 5)) +>Z : Symbol(Z, Decl(intersectionAsWeakTypeSource.ts, 1, 25)) +>xy : Symbol(xy, Decl(intersectionAsWeakTypeSource.ts, 5, 5)) + + +interface ViewStyle { +>ViewStyle : Symbol(ViewStyle, Decl(intersectionAsWeakTypeSource.ts, 7, 17)) + + view: number +>view : Symbol(ViewStyle.view, Decl(intersectionAsWeakTypeSource.ts, 10, 21)) + + styleMedia: string +>styleMedia : Symbol(ViewStyle.styleMedia, Decl(intersectionAsWeakTypeSource.ts, 11, 16)) +} +type Brand = number & { __brand: T } +>Brand : Symbol(Brand, Decl(intersectionAsWeakTypeSource.ts, 13, 1)) +>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 14, 11)) +>__brand : Symbol(__brand, Decl(intersectionAsWeakTypeSource.ts, 14, 26)) +>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 14, 11)) + +declare function create(styles: T): { [P in keyof T]: Brand }; +>create : Symbol(create, Decl(intersectionAsWeakTypeSource.ts, 14, 39)) +>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24)) +>s : Symbol(s, Decl(intersectionAsWeakTypeSource.ts, 15, 37)) +>ViewStyle : Symbol(ViewStyle, Decl(intersectionAsWeakTypeSource.ts, 7, 17)) +>styles : Symbol(styles, Decl(intersectionAsWeakTypeSource.ts, 15, 62)) +>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24)) +>P : Symbol(P, Decl(intersectionAsWeakTypeSource.ts, 15, 77)) +>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24)) +>Brand : Symbol(Brand, Decl(intersectionAsWeakTypeSource.ts, 13, 1)) +>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24)) +>P : Symbol(P, Decl(intersectionAsWeakTypeSource.ts, 15, 77)) + +const wrapped = create({ first: { view: 0, styleMedia: "???" } }); +>wrapped : Symbol(wrapped, Decl(intersectionAsWeakTypeSource.ts, 16, 5)) +>create : Symbol(create, Decl(intersectionAsWeakTypeSource.ts, 14, 39)) +>first : Symbol(first, Decl(intersectionAsWeakTypeSource.ts, 16, 24)) +>view : Symbol(view, Decl(intersectionAsWeakTypeSource.ts, 16, 33)) +>styleMedia : Symbol(styleMedia, Decl(intersectionAsWeakTypeSource.ts, 16, 42)) + +const vs: ViewStyle = wrapped.first // error, first is a branded number +>vs : Symbol(vs, Decl(intersectionAsWeakTypeSource.ts, 17, 5)) +>ViewStyle : Symbol(ViewStyle, Decl(intersectionAsWeakTypeSource.ts, 7, 17)) +>wrapped.first : Symbol(first, Decl(intersectionAsWeakTypeSource.ts, 16, 24)) +>wrapped : Symbol(wrapped, Decl(intersectionAsWeakTypeSource.ts, 16, 5)) +>first : Symbol(first, Decl(intersectionAsWeakTypeSource.ts, 16, 24)) + diff --git a/tests/baselines/reference/intersectionAsWeakTypeSource.types b/tests/baselines/reference/intersectionAsWeakTypeSource.types new file mode 100644 index 0000000000..2362f7c92c --- /dev/null +++ b/tests/baselines/reference/intersectionAsWeakTypeSource.types @@ -0,0 +1,60 @@ +=== tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts === +interface X { x: string } +>x : string + +interface Y { y: number } +>y : number + +interface Z { z?: boolean } +>z : boolean + +type XY = X & Y; +>XY : XY + +const xy: XY = {x: 'x', y: 10}; +>xy : XY +>{x: 'x', y: 10} : { x: string; y: number; } +>x : string +>'x' : "x" +>y : number +>10 : 10 + +const z1: Z = xy; // error, {xy} doesn't overlap with {z} +>z1 : Z +>xy : XY + + +interface ViewStyle { + view: number +>view : number + + styleMedia: string +>styleMedia : string +} +type Brand = number & { __brand: T } +>Brand : Brand +>__brand : T + +declare function create(styles: T): { [P in keyof T]: Brand }; +>create : (styles: T) => { [P in keyof T]: Brand; } +>s : string +>styles : T + +const wrapped = create({ first: { view: 0, styleMedia: "???" } }); +>wrapped : { first: Brand<{ view: number; styleMedia: string; }>; } +>create({ first: { view: 0, styleMedia: "???" } }) : { first: Brand<{ view: number; styleMedia: string; }>; } +>create : (styles: T) => { [P in keyof T]: Brand; } +>{ first: { view: 0, styleMedia: "???" } } : { first: { view: number; styleMedia: string; }; } +>first : { view: number; styleMedia: string; } +>{ view: 0, styleMedia: "???" } : { view: number; styleMedia: string; } +>view : number +>0 : 0 +>styleMedia : string +>"???" : "???" + +const vs: ViewStyle = wrapped.first // error, first is a branded number +>vs : ViewStyle +>wrapped.first : Brand<{ view: number; styleMedia: string; }> +>wrapped : { first: Brand<{ view: number; styleMedia: string; }>; } +>first : Brand<{ view: number; styleMedia: string; }> + diff --git a/tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts b/tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts new file mode 100644 index 0000000000..1ebe78b05f --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts @@ -0,0 +1,18 @@ +interface X { x: string } +interface Y { y: number } +interface Z { z?: boolean } + +type XY = X & Y; +const xy: XY = {x: 'x', y: 10}; + +const z1: Z = xy; // error, {xy} doesn't overlap with {z} + + +interface ViewStyle { + view: number + styleMedia: string +} +type Brand = number & { __brand: T } +declare function create(styles: T): { [P in keyof T]: Brand }; +const wrapped = create({ first: { view: 0, styleMedia: "???" } }); +const vs: ViewStyle = wrapped.first // error, first is a branded number