@@ -9853,7 +9853,7 @@ namespace ts {
9853
9853
}
9854
9854
9855
9855
function getPropertiesOfType(type: Type): Symbol[] {
9856
- type = getApparentType(getReducedType( type) );
9856
+ type = getApparentType(type);
9857
9857
return type.flags & TypeFlags.UnionOrIntersection ?
9858
9858
getPropertiesOfUnionOrIntersectionType(<UnionType>type) :
9859
9859
getPropertiesOfObjectType(type);
@@ -10195,6 +10195,7 @@ namespace ts {
10195
10195
* type itself.
10196
10196
*/
10197
10197
function getApparentType(type: Type): Type {
10198
+ type = getReducedType(type);
10198
10199
const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type;
10199
10200
return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(<MappedType>t) :
10200
10201
t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
@@ -10352,15 +10353,21 @@ namespace ts {
10352
10353
* no constituent property has type 'never', but the intersection of the constituent property types is 'never'.
10353
10354
*/
10354
10355
function getReducedType(type: Type): Type {
10355
- if (type.flags & TypeFlags.Union && (<UnionType>type).objectFlags & ObjectFlags.ContainsIntersections ) {
10356
+ if (type.flags & TypeFlags.Union && (<UnionType>type).objectFlags & ObjectFlags.ContainsReducibles ) {
10356
10357
return (<UnionType>type).resolvedReducedType || ((<UnionType>type).resolvedReducedType = getReducedUnionType(<UnionType>type));
10357
10358
}
10358
10359
else if (type.flags & TypeFlags.Intersection) {
10359
10360
if (!((<IntersectionType>type).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) {
10360
10361
(<IntersectionType>type).objectFlags |= ObjectFlags.IsNeverIntersectionComputed |
10361
10362
(some(getPropertiesOfUnionOrIntersectionType(<IntersectionType>type), isDiscriminantWithNeverType) ? ObjectFlags.IsNeverIntersection : 0);
10362
10363
}
10363
- return (<IntersectionType>type).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type;
10364
+ if ((<IntersectionType>type).objectFlags & ObjectFlags.IsNeverIntersection) {
10365
+ return neverType;
10366
+ }
10367
+ return (<IntersectionType>type).resolvedReducedType || ((<IntersectionType>type).resolvedReducedType = getReducedIntersectionType(<IntersectionType>type));
10368
+ }
10369
+ else if (type.flags & TypeFlags.Conditional) {
10370
+ return getReducedConditionalType(type as ConditionalType);
10364
10371
}
10365
10372
return type;
10366
10373
}
@@ -10377,6 +10384,18 @@ namespace ts {
10377
10384
return reduced;
10378
10385
}
10379
10386
10387
+ function getReducedIntersectionType(type: IntersectionType) {
10388
+ const reducedTypes = sameMap(type.types, getReducedType);
10389
+ if (reducedTypes === type.types) {
10390
+ return type;
10391
+ }
10392
+ const reduced = getIntersectionType(reducedTypes);
10393
+ if (reduced.flags & TypeFlags.Intersection) {
10394
+ (<IntersectionType>reduced).resolvedReducedType = reduced;
10395
+ }
10396
+ return reduced;
10397
+ }
10398
+
10380
10399
function isDiscriminantWithNeverType(prop: Symbol) {
10381
10400
return !(prop.flags & SymbolFlags.Optional) &&
10382
10401
(getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant &&
@@ -10430,7 +10449,7 @@ namespace ts {
10430
10449
* maps primitive types and type parameters are to their apparent types.
10431
10450
*/
10432
10451
function getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[] {
10433
- return getSignaturesOfStructuredType(getApparentType(getReducedType( type) ), kind);
10452
+ return getSignaturesOfStructuredType(getApparentType(type), kind);
10434
10453
}
10435
10454
10436
10455
function getIndexInfoOfStructuredType(type: Type, kind: IndexKind): IndexInfo | undefined {
@@ -10448,13 +10467,13 @@ namespace ts {
10448
10467
// Return the indexing info of the given kind in the given type. Creates synthetic union index types when necessary and
10449
10468
// maps primitive types and type parameters are to their apparent types.
10450
10469
function getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined {
10451
- return getIndexInfoOfStructuredType(getApparentType(getReducedType( type) ), kind);
10470
+ return getIndexInfoOfStructuredType(getApparentType(type), kind);
10452
10471
}
10453
10472
10454
10473
// Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
10455
10474
// maps primitive types and type parameters are to their apparent types.
10456
10475
function getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined {
10457
- return getIndexTypeOfStructuredType(getApparentType(getReducedType( type) ), kind);
10476
+ return getIndexTypeOfStructuredType(getApparentType(type), kind);
10458
10477
}
10459
10478
10460
10479
function getImplicitIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined {
@@ -12035,7 +12054,7 @@ namespace ts {
12035
12054
}
12036
12055
}
12037
12056
const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) |
12038
- (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0);
12057
+ (includes & TypeFlags.ReducibleNotUnion ? ObjectFlags.ContainsReducibles : 0);
12039
12058
return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments);
12040
12059
}
12041
12060
@@ -12750,6 +12769,25 @@ namespace ts {
12750
12769
return type[cache] = type;
12751
12770
}
12752
12771
12772
+ function getReducedConditionalType(type: ConditionalType): Type {
12773
+ const checkType = type.checkType;
12774
+ const extendsType = getInferredExtendsTypeOfConditional(type);
12775
+
12776
+ if (!isGenericObjectType(checkType) && !isGenericIndexType(checkType) && !isGenericObjectType(extendsType) && !isGenericIndexType(extendsType)) {
12777
+ const result = getConditionalSimplificationState(checkType, extendsType);
12778
+ switch (result) {
12779
+ case ConditionalSimplificationState.True:
12780
+ return getReducedType(getInferredTrueTypeFromConditionalType(type));
12781
+ case ConditionalSimplificationState.False:
12782
+ return getReducedType(getFalseTypeFromConditionalType(type));
12783
+ case ConditionalSimplificationState.Both:
12784
+ return getUnionType([getReducedType(getInferredTrueTypeFromConditionalType(type)), getReducedType(getFalseTypeFromConditionalType(type))]);
12785
+ // None: Fall out and return `type`
12786
+ }
12787
+ }
12788
+ return type;
12789
+ }
12790
+
12753
12791
function getSimplifiedConditionalType(type: ConditionalType, writing: boolean) {
12754
12792
const checkType = type.checkType;
12755
12793
const extendsType = type.extendsType;
@@ -12821,7 +12859,7 @@ namespace ts {
12821
12859
// In the following we resolve T[K] to the type of the property in T selected by K.
12822
12860
// We treat boolean as different from other unions to improve errors;
12823
12861
// skipping straight to getPropertyTypeForIndexType gives errors with 'boolean' instead of 'true'.
12824
- const apparentObjectType = getApparentType(getReducedType( objectType) );
12862
+ const apparentObjectType = getApparentType(objectType);
12825
12863
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) {
12826
12864
const propTypes: Type[] = [];
12827
12865
let wasMissingProp = false;
@@ -12888,6 +12926,14 @@ namespace ts {
12888
12926
return type;
12889
12927
}
12890
12928
12929
+ function isTypeDeferredTypeReference(type: Type) {
12930
+ return !!(getObjectFlags(type) & ObjectFlags.Reference) && !!(type as TypeReference).node;
12931
+ }
12932
+
12933
+ function getInferredExtendsTypeOfConditional(type: ConditionalType) {
12934
+ return instantiateType(type.root.extendsType, type.combinedMapper || type.mapper);
12935
+ }
12936
+
12891
12937
function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined): Type {
12892
12938
const checkType = instantiateType(root.checkType, mapper);
12893
12939
const extendsType = instantiateType(root.extendsType, mapper);
@@ -12913,28 +12959,17 @@ namespace ts {
12913
12959
// Instantiate the extends type including inferences for 'infer T' type parameters
12914
12960
const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
12915
12961
// We attempt to resolve the conditional type only when the check and extends types are non-generic
12916
- if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType)) {
12917
- if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
12918
- return instantiateType(root.trueType, combinedMapper || mapper);
12919
- }
12920
- // Return union of trueType and falseType for 'any' since it matches anything
12921
- if (checkType.flags & TypeFlags.Any) {
12922
- return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]);
12923
- }
12924
- // Return falseType for a definitely false extends check. We check an instantiations of the two
12925
- // types with type parameters mapped to the wildcard type, the most permissive instantiations
12926
- // possible (the wildcard type is assignable to and from all types). If those are not related,
12927
- // then no instantiations will be and we can just return the false branch type.
12928
- if (!isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType))) {
12929
- return instantiateType(root.falseType, mapper);
12930
- }
12931
- // Return trueType for a definitely true extends check. We check instantiations of the two
12932
- // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
12933
- // that has no constraint. This ensures that, for example, the type
12934
- // type Foo<T extends { x: any }> = T extends { x: string } ? string : number
12935
- // doesn't immediately resolve to 'string' instead of being deferred.
12936
- if (isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) {
12937
- return instantiateType(root.trueType, combinedMapper || mapper);
12962
+ if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType)
12963
+ && !isTypeDeferredTypeReference(checkType) && !isTypeDeferredTypeReference(inferredExtendsType)) {
12964
+ const result = getConditionalSimplificationState(checkType, inferredExtendsType);
12965
+ switch (result) {
12966
+ case ConditionalSimplificationState.True:
12967
+ return instantiateType(root.trueType, combinedMapper || mapper);
12968
+ case ConditionalSimplificationState.Both:
12969
+ return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]);
12970
+ case ConditionalSimplificationState.False:
12971
+ return instantiateType(root.falseType, mapper);
12972
+ // None: Fall out and defer
12938
12973
}
12939
12974
}
12940
12975
// Return a deferred type for a check that is neither definitely true nor definitely false
@@ -12950,6 +12985,39 @@ namespace ts {
12950
12985
return result;
12951
12986
}
12952
12987
12988
+ const enum ConditionalSimplificationState {
12989
+ None = 0,
12990
+ True = 1,
12991
+ False = 2,
12992
+ Both = True | False,
12993
+ }
12994
+
12995
+ function getConditionalSimplificationState(checkType: Type, inferredExtendsType: Type): ConditionalSimplificationState {
12996
+ if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
12997
+ return ConditionalSimplificationState.True;
12998
+ }
12999
+ // Return union of trueType and falseType for 'any' since it matches anything
13000
+ if (checkType.flags & TypeFlags.Any) {
13001
+ return ConditionalSimplificationState.Both;
13002
+ }
13003
+ // Return falseType for a definitely false extends check. We check an instantiations of the two
13004
+ // types with type parameters mapped to the wildcard type, the most permissive instantiations
13005
+ // possible (the wildcard type is assignable to and from all types). If those are not related,
13006
+ // then no instantiations will be and we can just return the false branch type.
13007
+ if (!isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType))) {
13008
+ return ConditionalSimplificationState.False;
13009
+ }
13010
+ // Return trueType for a definitely true extends check. We check instantiations of the two
13011
+ // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
13012
+ // that has no constraint. This ensures that, for example, the type
13013
+ // type Foo<T extends { x: any }> = T extends { x: string } ? string : number
13014
+ // doesn't immediately resolve to 'string' instead of being deferred.
13015
+ if (isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) {
13016
+ return ConditionalSimplificationState.True;
13017
+ }
13018
+ return ConditionalSimplificationState.None;
13019
+ }
13020
+
12953
13021
function getTrueTypeFromConditionalType(type: ConditionalType) {
12954
13022
return type.resolvedTrueType || (type.resolvedTrueType = instantiateType(type.root.trueType, type.mapper));
12955
13023
}
@@ -14986,7 +15054,7 @@ namespace ts {
14986
15054
while (true) {
14987
15055
const t = isFreshLiteralType(type) ? (<FreshableType>type).regularType :
14988
15056
getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).node ? createTypeReference((<TypeReference>type).target, getTypeArguments(<TypeReference>type)) :
14989
- type.flags & TypeFlags.UnionOrIntersection ? getReducedType(type) :
15057
+ type.flags & TypeFlags.Reducible ? getSimplifiedType( getReducedType(type), writing ) :
14990
15058
type.flags & TypeFlags.Substitution ? writing ? (<SubstitutionType>type).baseType : (<SubstitutionType>type).substitute :
14991
15059
type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) :
14992
15060
type;
0 commit comments