@@ -5352,12 +5352,12 @@ namespace ts {
53525352 }
53535353 }
53545354
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
53585358 // types are known not to circularly reference themselves (as is the case with union types created by
53595359 // 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.
53615361 // For example, "type Item = string | (() => Item" is a named type that circularly references itself.
53625362 function getUnionType(types: Type[], subtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
53635363 if (types.length === 0) {
@@ -5379,15 +5379,23 @@ namespace ts {
53795379 typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
53805380 neverType;
53815381 }
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;
53845389 }
5385- const id = getTypeListId(typeSet);
5390+ if (types.length === 1) {
5391+ return types[0];
5392+ }
5393+ const id = getTypeListId(types);
53865394 let type = unionTypes[id];
53875395 if (!type) {
5388- const propagatedFlags = getPropagatingFlagsOfTypes(typeSet , /*excludeKinds*/ TypeFlags.Nullable);
5396+ const propagatedFlags = getPropagatingFlagsOfTypes(types , /*excludeKinds*/ TypeFlags.Nullable);
53895397 type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | propagatedFlags);
5390- type.types = typeSet ;
5398+ type.types = types ;
53915399 type.aliasSymbol = aliasSymbol;
53925400 type.aliasTypeArguments = aliasTypeArguments;
53935401 }
@@ -8168,12 +8176,12 @@ namespace ts {
81688176 }
81698177
81708178 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);
81738183 }
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;
81778185 }
81788186
81798187 function isIncomplete(flowType: FlowType) {
0 commit comments