mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2459,7 +2459,6 @@ declare namespace ts {
|
||||
Instantiable = 63176704,
|
||||
StructuredOrInstantiable = 66846720,
|
||||
Narrowable = 133970943,
|
||||
NotUnionOrUnit = 67637251,
|
||||
}
|
||||
export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
|
||||
export interface Type {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user