Consistent narrowing to 'never' in conditional and switch statements (#39191)

* Allow unions and unit types to narrow to 'never'

* Remove odd check for TypeFlags.NotUnionOrUnit

* Accept new baselines

* Accept new API baselines
This commit is contained in:
Anders Hejlsberg
2020-06-29 15:25:00 -07:00
committed by GitHub
parent b448540644
commit 9458f8acab
7 changed files with 15 additions and 39 deletions
+3 -9
View File
@@ -20580,7 +20580,7 @@ namespace ts {
}
function createFlowType(type: Type, incomplete: boolean): FlowType {
return incomplete ? { flags: 0, type } : type;
return incomplete ? { flags: 0, type: type.flags & TypeFlags.Never ? silentNeverType : type } : type;
}
// An evolving array type tracks the element types that have so far been seen in an
@@ -21168,9 +21168,7 @@ namespace ts {
if (narrowedType === nonEvolvingType) {
return flowType;
}
const incomplete = isIncomplete(flowType);
const resultType = incomplete && narrowedType.flags & TypeFlags.Never ? silentNeverType : narrowedType;
return createFlowType(resultType, incomplete);
return createFlowType(narrowedType, isIncomplete(flowType));
}
function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType {
@@ -21508,15 +21506,11 @@ namespace ts {
assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined;
return getTypeWithFacts(type, facts);
}
if (type.flags & TypeFlags.NotUnionOrUnit) {
return type;
}
if (assumeTrue) {
const filterFn: (t: Type) => boolean = operator === SyntaxKind.EqualsEqualsToken ?
(t => areTypesComparable(t, valueType) || isCoercibleUnderDoubleEquals(t, valueType)) :
t => areTypesComparable(t, valueType);
const narrowedType = filterType(type, filterFn);
return narrowedType.flags & TypeFlags.Never ? type : replacePrimitivesWithLiterals(narrowedType, valueType);
return replacePrimitivesWithLiterals(filterType(type, filterFn), valueType);
}
if (isUnitType(valueType)) {
const regularType = getRegularTypeOfLiteralType(valueType);
-1
View File
@@ -4861,7 +4861,6 @@ namespace ts {
// 'Narrowable' types are types where narrowing actually narrows.
// This *should* be every type other than null, undefined, void, and never
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
NotUnionOrUnit = Any | Unknown | ESSymbol | Object | NonPrimitive,
/* @internal */
NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | StructuredOrInstantiable,
// The following flags are aggregated during union and intersection type construction
-1
View File
@@ -2459,7 +2459,6 @@ declare namespace ts {
Instantiable = 63176704,
StructuredOrInstantiable = 66846720,
Narrowable = 133970943,
NotUnionOrUnit = 67637251,
}
export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
export interface Type {
-1
View File
@@ -2459,7 +2459,6 @@ declare namespace ts {
Instantiable = 63176704,
StructuredOrInstantiable = 66846720,
Narrowable = 133970943,
NotUnionOrUnit = 67637251,
}
export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
export interface Type {
@@ -320,7 +320,7 @@ function f3(m: Message) {
>"X" : "X"
m; // never
>m : Message
>m : never
}
}
@@ -1,14 +1,9 @@
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(17,5): error TS2367: This condition will always return 'false' since the types 'I1 & I3' and 'I2' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(17,16): error TS2367: This condition will always return 'false' since the types 'I2' and 'I1 & I3' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(19,10): error TS2367: This condition will always return 'true' since the types 'I1 & I3' and 'I2' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(19,21): error TS2367: This condition will always return 'true' since the types 'I2' and 'I1 & I3' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(21,10): error TS2367: This condition will always return 'false' since the types 'I1 & I3' and 'I2' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(21,20): error TS2367: This condition will always return 'false' since the types 'I2' and 'I1 & I3' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(23,10): error TS2367: This condition will always return 'true' since the types 'I1 & I3' and 'I2' have no overlap.
tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts(23,20): error TS2367: This condition will always return 'true' since the types 'I2' and 'I1 & I3' have no overlap.
==== tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts (8 errors) ====
==== tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersectionTypes01.ts (3 errors) ====
interface I1 {
p1: number
}
@@ -34,18 +29,8 @@ tests/cases/conformance/types/typeRelationships/comparable/equalityWithIntersect
else if (y !== z || z !== y) {
~~~~~~~
!!! error TS2367: This condition will always return 'true' since the types 'I1 & I3' and 'I2' have no overlap.
~~~~~~~
!!! error TS2367: This condition will always return 'true' since the types 'I2' and 'I1 & I3' have no overlap.
}
else if (y == z || z == y) {
~~~~~~
!!! error TS2367: This condition will always return 'false' since the types 'I1 & I3' and 'I2' have no overlap.
~~~~~~
!!! error TS2367: This condition will always return 'false' since the types 'I2' and 'I1 & I3' have no overlap.
}
else if (y != z || z != y) {
~~~~~~
!!! error TS2367: This condition will always return 'true' since the types 'I1 & I3' and 'I2' have no overlap.
~~~~~~
!!! error TS2367: This condition will always return 'true' since the types 'I2' and 'I1 & I3' have no overlap.
}
@@ -47,24 +47,24 @@ else if (y !== z || z !== y) {
>y : I1 & I3
>z : I2
>z !== y : boolean
>z : I2
>y : I1 & I3
>z : never
>y : never
}
else if (y == z || z == y) {
>y == z || z == y : boolean
>y == z : boolean
>y : I1 & I3
>z : I2
>y : never
>z : never
>z == y : boolean
>z : I2
>y : I1 & I3
>z : never
>y : never
}
else if (y != z || z != y) {
>y != z || z != y : boolean
>y != z : boolean
>y : I1 & I3
>z : I2
>y : never
>z : never
>z != y : boolean
>z : I2
>y : I1 & I3
>z : never
>y : never
}