Allow intersections (and substitutions) to be checks against discriminable unions (#36663)

This commit is contained in:
Wesley Wigham
2020-02-10 15:26:46 -08:00
committed by GitHub
parent 70e6f5b8a0
commit aece8c06b0
5 changed files with 126 additions and 3 deletions

View File

@@ -15901,7 +15901,7 @@ namespace ts {
// with respect to T. We do not report errors here, as we will use the existing
// error result from checking each constituent of the union.
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Union) {
const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object);
const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution);
if (objectOnlyTarget.flags & TypeFlags.Union) {
const result = typeRelatedToDiscriminatedType(source, objectOnlyTarget as UnionType);
if (result) {
@@ -15998,7 +15998,7 @@ namespace ts {
// NOTE: See ~/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts
// for examples.
const sourceProperties = getPropertiesOfObjectType(source);
const sourceProperties = getPropertiesOfType(source);
const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target);
if (!sourcePropertiesFiltered) return Ternary.False;
@@ -16037,7 +16037,7 @@ namespace ts {
outer: for (const type of target.types) {
for (let i = 0; i < sourcePropertiesFiltered.length; i++) {
const sourceProperty = sourcePropertiesFiltered[i];
const targetProperty = getPropertyOfObjectType(type, sourceProperty.escapedName);
const targetProperty = getPropertyOfType(type, sourceProperty.escapedName);
if (!targetProperty) continue outer;
if (sourceProperty === targetProperty) continue;
// We compare the source property to the target in the context of a single discriminant type.

View File

@@ -0,0 +1,21 @@
//// [discriminableUnionWithIntersectedMembers.ts]
// regression test for https://github.com/microsoft/TypeScript/issues/33243
type X =
| { x: 'x', y: number } & { y: number }
| { x: 'y', y: number, z?: boolean } & { y: number }
// error
const x: X = 4 as any as { x: 'x' | 'y', y: number };
type Y =
| { x: 'x', y: number }
| { x: 'y', y: number, z?: boolean }
// no error
const y: Y = 4 as any as { x: 'x' | 'y', y: number };
//// [discriminableUnionWithIntersectedMembers.js]
// error
var x = 4;
// no error
var y = 4;

View File

@@ -0,0 +1,42 @@
=== tests/cases/compiler/discriminableUnionWithIntersectedMembers.ts ===
// regression test for https://github.com/microsoft/TypeScript/issues/33243
type X =
>X : Symbol(X, Decl(discriminableUnionWithIntersectedMembers.ts, 0, 0))
| { x: 'x', y: number } & { y: number }
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 2, 4))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 2, 12))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 2, 28))
| { x: 'y', y: number, z?: boolean } & { y: number }
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 3, 4))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 3, 12))
>z : Symbol(z, Decl(discriminableUnionWithIntersectedMembers.ts, 3, 23))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 3, 41))
// error
const x: X = 4 as any as { x: 'x' | 'y', y: number };
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 6, 5))
>X : Symbol(X, Decl(discriminableUnionWithIntersectedMembers.ts, 0, 0))
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 6, 26))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 6, 40))
type Y =
>Y : Symbol(Y, Decl(discriminableUnionWithIntersectedMembers.ts, 6, 53))
| { x: 'x', y: number }
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 9, 4))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 9, 12))
| { x: 'y', y: number, z?: boolean }
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 10, 4))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 10, 12))
>z : Symbol(z, Decl(discriminableUnionWithIntersectedMembers.ts, 10, 23))
// no error
const y: Y = 4 as any as { x: 'x' | 'y', y: number };
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 13, 5))
>Y : Symbol(Y, Decl(discriminableUnionWithIntersectedMembers.ts, 6, 53))
>x : Symbol(x, Decl(discriminableUnionWithIntersectedMembers.ts, 13, 26))
>y : Symbol(y, Decl(discriminableUnionWithIntersectedMembers.ts, 13, 40))

View File

@@ -0,0 +1,46 @@
=== tests/cases/compiler/discriminableUnionWithIntersectedMembers.ts ===
// regression test for https://github.com/microsoft/TypeScript/issues/33243
type X =
>X : X
| { x: 'x', y: number } & { y: number }
>x : "x"
>y : number
>y : number
| { x: 'y', y: number, z?: boolean } & { y: number }
>x : "y"
>y : number
>z : boolean
>y : number
// error
const x: X = 4 as any as { x: 'x' | 'y', y: number };
>x : X
>4 as any as { x: 'x' | 'y', y: number } : { x: "x" | "y"; y: number; }
>4 as any : any
>4 : 4
>x : "x" | "y"
>y : number
type Y =
>Y : Y
| { x: 'x', y: number }
>x : "x"
>y : number
| { x: 'y', y: number, z?: boolean }
>x : "y"
>y : number
>z : boolean
// no error
const y: Y = 4 as any as { x: 'x' | 'y', y: number };
>y : Y
>4 as any as { x: 'x' | 'y', y: number } : { x: "x" | "y"; y: number; }
>4 as any : any
>4 : 4
>x : "x" | "y"
>y : number

View File

@@ -0,0 +1,14 @@
// regression test for https://github.com/microsoft/TypeScript/issues/33243
type X =
| { x: 'x', y: number } & { y: number }
| { x: 'y', y: number, z?: boolean } & { y: number }
// error
const x: X = 4 as any as { x: 'x' | 'y', y: number };
type Y =
| { x: 'x', y: number }
| { x: 'y', y: number, z?: boolean }
// no error
const y: Y = 4 as any as { x: 'x' | 'y', y: number };