@@ -16125,7 +16125,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1612516125 }
1612616126
1612716127 function insertType(types: Type[], type: Type): boolean {
16128- const index = binarySearch(types, type, getTypeId, compareValues);
16128+ // TODO(jakebailey): we already have insertSorted and should use it here (adding the perf optimization?)
16129+ const len = types.length;
16130+ // Perf optimization (measure?); check the last element first as we often insert in order.
16131+ const index = len && type.id > types[len - 1].id ? ~len : binarySearch(types, type, getTypeId, compareValues);
1612916132 if (index < 0) {
1613016133 types.splice(~index, 0, type);
1613116134 return true;
@@ -16147,11 +16150,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1614716150 if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType;
1614816151 }
1614916152 else {
16150- const len = typeSet.length;
16151- const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues);
16152- if (index < 0) {
16153- typeSet.splice(~index, 0, type);
16154- }
16153+ insertType(typeSet, type);
1615516154 }
1615616155 }
1615716156 return includes;
@@ -16439,15 +16438,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1643916438 return links.resolvedType;
1644016439 }
1644116440
16442- function addTypeToIntersection(typeSet: Map<string, Type> , includes: TypeFlags, type: Type) {
16441+ function addTypeToIntersection(typeSet: Type[] , includes: TypeFlags, type: Type) {
1644316442 const flags = type.flags;
1644416443 if (flags & TypeFlags.Intersection) {
1644516444 return addTypesToIntersection(typeSet, includes, (type as IntersectionType).types);
1644616445 }
1644716446 if (isEmptyAnonymousObjectType(type)) {
1644816447 if (!(includes & TypeFlags.IncludesEmptyObject)) {
1644916448 includes |= TypeFlags.IncludesEmptyObject;
16450- typeSet.set(type.id.toString() , type);
16449+ insertType(typeSet , type);
1645116450 }
1645216451 }
1645316452 else {
@@ -16459,13 +16458,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1645916458 includes |= TypeFlags.IncludesMissingType;
1646016459 type = undefinedType;
1646116460 }
16462- if (!typeSet.has(type.id.toString())) {
16461+ const inserted = insertType(typeSet, type);
16462+ if (inserted) {
1646316463 if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) {
1646416464 // We have seen two distinct unit types which means we should reduce to an
1646516465 // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen.
1646616466 includes |= TypeFlags.NonPrimitive;
1646716467 }
16468- typeSet.set(type.id.toString(), type);
1646916468 }
1647016469 }
1647116470 includes |= flags & TypeFlags.IncludesMask;
@@ -16475,7 +16474,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1647516474
1647616475 // Add the given types to the given type set. Order is preserved, freshness is removed from literal
1647716476 // types, duplicates are removed, and nested types of the given kind are flattened into the set.
16478- function addTypesToIntersection(typeSet: Map<string, Type> , includes: TypeFlags, types: readonly Type[]) {
16477+ function addTypesToIntersection(typeSet: Type[] , includes: TypeFlags, types: readonly Type[]) {
1647916478 for (const type of types) {
1648016479 includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type));
1648116480 }
@@ -16618,9 +16617,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1661816617 // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
1661916618 // for intersections of types with signatures can be deterministic.
1662016619 function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type {
16621- const typeMembershipMap: Map<string, Type> = new Map();
16622- const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types);
16623- const typeSet: Type[] = arrayFrom(typeMembershipMap.values());
16620+ const typeSet: Type[] = [];
16621+ const includes = addTypesToIntersection(typeSet, 0 as TypeFlags, types);
1662416622 // An intersection type is considered empty if it contains
1662516623 // the type never, or
1662616624 // more than one unit type or,
0 commit comments