@@ -5352,12 +5352,12 @@ namespace ts {
5352
5352
}
5353
5353
}
5354
5354
5355
- // We deduplicate the constituent types based on object identity. If the subtypeReduction flag is
5356
- // specified we also reduce the constituent type set to only include types that aren't subtypes of
5357
- // other types. Subtype reduction is expensive for large union types and is possible only when union
5355
+ // We sort and deduplicate the constituent types based on object identity. If the subtypeReduction
5356
+ // flag is specified we also reduce the constituent type set to only include types that aren't subtypes
5357
+ // of other types. Subtype reduction is expensive for large union types and is possible only when union
5358
5358
// types are known not to circularly reference themselves (as is the case with union types created by
5359
5359
// expression constructs such as array literals and the || and ?: operators). Named types can
5360
- // circularly reference themselves and therefore cannot be deduplicated during their declaration.
5360
+ // circularly reference themselves and therefore cannot be subtype reduced during their declaration.
5361
5361
// For example, "type Item = string | (() => Item" is a named type that circularly references itself.
5362
5362
function getUnionType(types: Type[], subtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
5363
5363
if (types.length === 0) {
@@ -5379,15 +5379,23 @@ namespace ts {
5379
5379
typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
5380
5380
neverType;
5381
5381
}
5382
- else if (typeSet.length === 1) {
5383
- return typeSet[0];
5382
+ return getUnionTypeFromSortedList(typeSet, aliasSymbol, aliasTypeArguments);
5383
+ }
5384
+
5385
+ // This function assumes the constituent type list is sorted and deduplicated.
5386
+ function getUnionTypeFromSortedList(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
5387
+ if (types.length === 0) {
5388
+ return neverType;
5384
5389
}
5385
- const id = getTypeListId(typeSet);
5390
+ if (types.length === 1) {
5391
+ return types[0];
5392
+ }
5393
+ const id = getTypeListId(types);
5386
5394
let type = unionTypes[id];
5387
5395
if (!type) {
5388
- const propagatedFlags = getPropagatingFlagsOfTypes(typeSet , /*excludeKinds*/ TypeFlags.Nullable);
5396
+ const propagatedFlags = getPropagatingFlagsOfTypes(types , /*excludeKinds*/ TypeFlags.Nullable);
5389
5397
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | propagatedFlags);
5390
- type.types = typeSet ;
5398
+ type.types = types ;
5391
5399
type.aliasSymbol = aliasSymbol;
5392
5400
type.aliasTypeArguments = aliasTypeArguments;
5393
5401
}
@@ -8168,12 +8176,12 @@ namespace ts {
8168
8176
}
8169
8177
8170
8178
function filterType(type: Type, f: (t: Type) => boolean): Type {
8171
- if (!(type.flags & TypeFlags.Union)) {
8172
- return f(type) ? type : neverType;
8179
+ if (type.flags & TypeFlags.Union) {
8180
+ const types = (<UnionType>type).types;
8181
+ const filtered = filter(types, f);
8182
+ return filtered === types ? type : getUnionTypeFromSortedList(filtered);
8173
8183
}
8174
- const types = (<UnionType>type).types;
8175
- const filtered = filter(types, f);
8176
- return filtered === types ? type : getUnionType(filtered);
8184
+ return f(type) ? type : neverType;
8177
8185
}
8178
8186
8179
8187
function isIncomplete(flowType: FlowType) {
0 commit comments