Skip to content

Commit 4e040f7

Browse files
authored
Merge pull request #31374 from weswigham/defer-conditionals-with-simplification
Simplify conditionals upon comparison, rather than instantiation
2 parents bb9c5c9 + 8ba53b6 commit 4e040f7

5 files changed

+110
-192
lines changed

src/compiler/checker.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9044,7 +9044,7 @@ namespace ts {
90449044
}
90459045

90469046
function getSubstitutionType(typeVariable: TypeVariable, substitute: Type) {
9047-
if (substitute.flags & TypeFlags.AnyOrUnknown) {
9047+
if (substitute.flags & TypeFlags.AnyOrUnknown || substitute === typeVariable) {
90489048
return typeVariable;
90499049
}
90509050
const id = `${getTypeId(typeVariable)}>${getTypeId(substitute)}`;
@@ -10194,7 +10194,9 @@ namespace ts {
1019410194
}
1019510195

1019610196
function getSimplifiedType(type: Type, writing: boolean): Type {
10197-
return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type, writing) : type;
10197+
return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type, writing) :
10198+
type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(<ConditionalType>type, writing) :
10199+
type;
1019810200
}
1019910201

1020010202
function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) {
@@ -10257,6 +10259,32 @@ namespace ts {
1025710259
return type[cache] = type;
1025810260
}
1025910261

10262+
function getSimplifiedConditionalType(type: ConditionalType, writing: boolean) {
10263+
const falseType = getFalseTypeFromConditionalType(type);
10264+
const trueType = getTrueTypeFromConditionalType(type);
10265+
const checkType = type.checkType;
10266+
const extendsType = type.extendsType;
10267+
// Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`.
10268+
if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) {
10269+
if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true
10270+
return getSimplifiedType(trueType, writing);
10271+
}
10272+
else if (isIntersectionEmpty(checkType, extendsType)) { // Always false
10273+
return neverType;
10274+
}
10275+
}
10276+
else if (trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType)) {
10277+
if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true
10278+
return neverType;
10279+
}
10280+
else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false
10281+
return getSimplifiedType(falseType, writing);
10282+
}
10283+
}
10284+
10285+
return type;
10286+
}
10287+
1026010288
function substituteIndexedMappedType(objectType: MappedType, index: Type) {
1026110289
const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]);
1026210290
const templateMapper = combineTypeMappers(objectType.mapper, mapper);
@@ -12431,10 +12459,10 @@ namespace ts {
1243112459
if (target.flags & TypeFlags.Substitution) {
1243212460
target = (<SubstitutionType>target).typeVariable;
1243312461
}
12434-
if (source.flags & TypeFlags.IndexedAccess) {
12462+
if (source.flags & TypeFlags.Simplifiable) {
1243512463
source = getSimplifiedType(source, /*writing*/ false);
1243612464
}
12437-
if (target.flags & TypeFlags.IndexedAccess) {
12465+
if (target.flags & TypeFlags.Simplifiable) {
1243812466
target = getSimplifiedType(target, /*writing*/ true);
1243912467
}
1244012468

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3966,6 +3966,8 @@ namespace ts {
39663966
StructuredOrInstantiable = StructuredType | Instantiable,
39673967
/* @internal */
39683968
ObjectFlagsType = Nullable | Never | Object | Union | Intersection,
3969+
/* @internal */
3970+
Simplifiable = IndexedAccess | Conditional,
39693971
// 'Narrowable' types are types where narrowing actually narrows.
39703972
// This *should* be every type other than null, undefined, void, and never
39713973
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,

0 commit comments

Comments
 (0)