Skip to content

Commit e64675e

Browse files
committed
Faster path for creating union types from filterType
1 parent f1ea145 commit e64675e

File tree

1 file changed

+22
-14
lines changed

1 file changed

+22
-14
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)