@@ -580,6 +580,21 @@ namespace ts {
580580 Both = Source | Target,
581581 }
582582
583+ const enum TypeIncludes {
584+ Any = 1 << 0,
585+ Undefined = 1 << 1,
586+ Null = 1 << 2,
587+ Never = 1 << 3,
588+ NonWideningType = 1 << 4,
589+ String = 1 << 5,
590+ Number = 1 << 6,
591+ ESSymbol = 1 << 7,
592+ LiteralOrUniqueESSymbol = 1 << 8,
593+ ObjectType = 1 << 9,
594+ EmptyObject = 1 << 10,
595+ Union = 1 << 11,
596+ }
597+
583598 const enum MembersOrExportsResolutionKind {
584599 resolvedExports = "resolvedExports",
585600 resolvedMembers = "resolvedMembers"
@@ -5540,6 +5555,8 @@ namespace ts {
55405555 sig.minArgumentCount = minArgumentCount;
55415556 sig.hasRestParameter = hasRestParameter;
55425557 sig.hasLiteralTypes = hasLiteralTypes;
5558+ sig.target = undefined;
5559+ sig.mapper = undefined;
55435560 return sig;
55445561 }
55455562
@@ -7443,21 +7460,6 @@ namespace ts {
74437460 return links.resolvedType;
74447461 }
74457462
7446- interface TypeSet extends Array<Type> {
7447- containsAny?: boolean;
7448- containsUndefined?: boolean;
7449- containsNull?: boolean;
7450- containsNever?: boolean;
7451- containsNonWideningType?: boolean;
7452- containsString?: boolean;
7453- containsNumber?: boolean;
7454- containsESSymbol?: boolean;
7455- containsLiteralOrUniqueESSymbol?: boolean;
7456- containsObjectType?: boolean;
7457- containsEmptyObject?: boolean;
7458- unionIndex?: number;
7459- }
7460-
74617463 function getTypeId(type: Type) {
74627464 return type.id;
74637465 }
@@ -7482,28 +7484,28 @@ namespace ts {
74827484 return false;
74837485 }
74847486
7485- function addTypeToUnion(typeSet: TypeSet , type: Type) {
7487+ function addTypeToUnion(typeSet: Type[], includes: TypeIncludes , type: Type) {
74867488 const flags = type.flags;
74877489 if (flags & TypeFlags.Union) {
7488- addTypesToUnion(typeSet, (<UnionType>type).types);
7490+ includes = addTypesToUnion(typeSet, includes , (<UnionType>type).types);
74897491 }
74907492 else if (flags & TypeFlags.Any) {
7491- typeSet.containsAny = true ;
7493+ includes |= TypeIncludes.Any ;
74927494 }
74937495 else if (!strictNullChecks && flags & TypeFlags.Nullable) {
7494- if (flags & TypeFlags.Undefined) typeSet.containsUndefined = true ;
7495- if (flags & TypeFlags.Null) typeSet.containsNull = true ;
7496- if (!(flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true ;
7496+ if (flags & TypeFlags.Undefined) includes |= TypeIncludes.Undefined ;
7497+ if (flags & TypeFlags.Null) includes |= TypeIncludes.Null ;
7498+ if (!(flags & TypeFlags.ContainsWideningType)) includes |= TypeIncludes.NonWideningType ;
74977499 }
74987500 else if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && isEmptyIntersectionType(<IntersectionType>type))) {
74997501 // We ignore 'never' types in unions. Likewise, we ignore intersections of unit types as they are
75007502 // another form of 'never' (in that they have an empty value domain). We could in theory turn
75017503 // intersections of unit types into 'never' upon construction, but deferring the reduction makes it
75027504 // easier to reason about their origin.
7503- if (flags & TypeFlags.String) typeSet.containsString = true ;
7504- if (flags & TypeFlags.Number) typeSet.containsNumber = true ;
7505- if (flags & TypeFlags.ESSymbol) typeSet.containsESSymbol = true ;
7506- if (flags & TypeFlags.StringOrNumberLiteralOrUnique) typeSet.containsLiteralOrUniqueESSymbol = true ;
7505+ if (flags & TypeFlags.String) includes |= TypeIncludes.String ;
7506+ if (flags & TypeFlags.Number) includes |= TypeIncludes.Number ;
7507+ if (flags & TypeFlags.ESSymbol) includes |= TypeIncludes.ESSymbol ;
7508+ if (flags & TypeFlags.StringOrNumberLiteralOrUnique) includes |= TypeIncludes.LiteralOrUniqueESSymbol ;
75077509 const len = typeSet.length;
75087510 const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues);
75097511 if (index < 0) {
@@ -7513,14 +7515,16 @@ namespace ts {
75137515 }
75147516 }
75157517 }
7518+ return includes;
75167519 }
75177520
75187521 // Add the given types to the given type set. Order is preserved, duplicates are removed,
75197522 // and nested types of the given kind are flattened into the set.
7520- function addTypesToUnion(typeSet: TypeSet, types: Type[]) {
7523+ function addTypesToUnion(typeSet: Type[], includes: TypeIncludes, types: Type[]): TypeIncludes {
75217524 for (const type of types) {
7522- addTypeToUnion(typeSet, type);
7525+ includes = addTypeToUnion(typeSet, includes , type);
75237526 }
7527+ return includes;
75247528 }
75257529
75267530 function containsIdenticalType(types: Type[], type: Type) {
@@ -7544,7 +7548,7 @@ namespace ts {
75447548 return false;
75457549 }
75467550
7547- function isSetOfLiteralsFromSameEnum(types: TypeSet ): boolean {
7551+ function isSetOfLiteralsFromSameEnum(types: Type[] ): boolean {
75487552 const first = types[0];
75497553 if (first.flags & TypeFlags.EnumLiteral) {
75507554 const firstEnum = getParentOfSymbol(first.symbol);
@@ -7560,7 +7564,7 @@ namespace ts {
75607564 return false;
75617565 }
75627566
7563- function removeSubtypes(types: TypeSet ) {
7567+ function removeSubtypes(types: Type[] ) {
75647568 if (types.length === 0 || isSetOfLiteralsFromSameEnum(types)) {
75657569 return;
75667570 }
@@ -7573,15 +7577,15 @@ namespace ts {
75737577 }
75747578 }
75757579
7576- function removeRedundantLiteralTypes(types: TypeSet ) {
7580+ function removeRedundantLiteralTypes(types: Type[], includes: TypeIncludes ) {
75777581 let i = types.length;
75787582 while (i > 0) {
75797583 i--;
75807584 const t = types[i];
75817585 const remove =
7582- t.flags & TypeFlags.StringLiteral && types.containsString ||
7583- t.flags & TypeFlags.NumberLiteral && types.containsNumber ||
7584- t.flags & TypeFlags.UniqueESSymbol && types.containsESSymbol ||
7586+ t.flags & TypeFlags.StringLiteral && includes & TypeIncludes.String ||
7587+ t.flags & TypeFlags.NumberLiteral && includes & TypeIncludes.Number ||
7588+ t.flags & TypeFlags.UniqueESSymbol && includes & TypeIncludes.ESSymbol ||
75857589 t.flags & TypeFlags.StringOrNumberLiteral && t.flags & TypeFlags.FreshLiteral && containsType(types, (<LiteralType>t).regularType);
75867590 if (remove) {
75877591 orderedRemoveItemAt(types, i);
@@ -7603,24 +7607,24 @@ namespace ts {
76037607 if (types.length === 1) {
76047608 return types[0];
76057609 }
7606- const typeSet = [] as TypeSet ;
7607- addTypesToUnion(typeSet, types);
7608- if (typeSet.containsAny ) {
7610+ const typeSet: Type [] = [] ;
7611+ const includes = addTypesToUnion(typeSet, 0 , types);
7612+ if (includes & TypeIncludes.Any ) {
76097613 return anyType;
76107614 }
76117615 switch (unionReduction) {
76127616 case UnionReduction.Literal:
7613- if (typeSet.containsLiteralOrUniqueESSymbol ) {
7614- removeRedundantLiteralTypes(typeSet);
7617+ if (includes & TypeIncludes.LiteralOrUniqueESSymbol ) {
7618+ removeRedundantLiteralTypes(typeSet, includes );
76157619 }
76167620 break;
76177621 case UnionReduction.Subtype:
76187622 removeSubtypes(typeSet);
76197623 break;
76207624 }
76217625 if (typeSet.length === 0) {
7622- return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType :
7623- typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
7626+ return includes & TypeIncludes.Null ? includes & TypeIncludes.NonWideningType ? nullType : nullWideningType :
7627+ includes & TypeIncludes.Undefined ? includes & TypeIncludes.NonWideningType ? undefinedType : undefinedWideningType :
76247628 neverType;
76257629 }
76267630 return getUnionTypeFromSortedList(typeSet, aliasSymbol, aliasTypeArguments);
@@ -7698,39 +7702,42 @@ namespace ts {
76987702 return links.resolvedType;
76997703 }
77007704
7701- function addTypeToIntersection(typeSet: TypeSet, type: Type) {
7702- if (type.flags & TypeFlags.Intersection) {
7703- addTypesToIntersection(typeSet, (<IntersectionType>type).types);
7705+ function addTypeToIntersection(typeSet: Type[], includes: TypeIncludes, type: Type) {
7706+ const flags = type.flags;
7707+ if (flags & TypeFlags.Intersection) {
7708+ includes = addTypesToIntersection(typeSet, includes, (<IntersectionType>type).types);
77047709 }
7705- else if (type. flags & TypeFlags.Any) {
7706- typeSet.containsAny = true ;
7710+ else if (flags & TypeFlags.Any) {
7711+ includes |= TypeIncludes.Any ;
77077712 }
7708- else if (type. flags & TypeFlags.Never) {
7709- typeSet.containsNever = true ;
7713+ else if (flags & TypeFlags.Never) {
7714+ includes |= TypeIncludes.Never ;
77107715 }
77117716 else if (getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type)) {
7712- typeSet.containsEmptyObject = true ;
7717+ includes |= TypeIncludes.EmptyObject ;
77137718 }
7714- else if ((strictNullChecks || !(type. flags & TypeFlags.Nullable)) && !contains(typeSet, type)) {
7715- if (type. flags & TypeFlags.Object) {
7716- typeSet.containsObjectType = true ;
7719+ else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !contains(typeSet, type)) {
7720+ if (flags & TypeFlags.Object) {
7721+ includes |= TypeIncludes.ObjectType ;
77177722 }
7718- if (type. flags & TypeFlags.Union && typeSet.unionIndex === undefined ) {
7719- typeSet.unionIndex = typeSet.length ;
7723+ if (flags & TypeFlags.Union) {
7724+ includes |= TypeIncludes.Union ;
77207725 }
7721- if (!(type. flags & TypeFlags.Object && (<ObjectType>type).objectFlags & ObjectFlags.Anonymous &&
7726+ if (!(flags & TypeFlags.Object && (<ObjectType>type).objectFlags & ObjectFlags.Anonymous &&
77227727 type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && containsIdenticalType(typeSet, type))) {
77237728 typeSet.push(type);
77247729 }
77257730 }
7731+ return includes;
77267732 }
77277733
77287734 // Add the given types to the given type set. Order is preserved, freshness is removed from literal
77297735 // types, duplicates are removed, and nested types of the given kind are flattened into the set.
7730- function addTypesToIntersection(typeSet: TypeSet , types: Type[]) {
7736+ function addTypesToIntersection(typeSet: Type[], includes: TypeIncludes , types: Type[]) {
77317737 for (const type of types) {
7732- addTypeToIntersection(typeSet, getRegularTypeOfLiteralType(type));
7738+ includes = addTypeToIntersection(typeSet, includes , getRegularTypeOfLiteralType(type));
77337739 }
7740+ return includes;
77347741 }
77357742
77367743 // We normalize combinations of intersection and union types based on the distributive property of the '&'
@@ -7747,27 +7754,27 @@ namespace ts {
77477754 if (types.length === 0) {
77487755 return emptyObjectType;
77497756 }
7750- const typeSet = [] as TypeSet ;
7751- addTypesToIntersection(typeSet, types);
7752- if (typeSet.containsNever ) {
7757+ const typeSet: Type [] = [] ;
7758+ const includes = addTypesToIntersection(typeSet, 0 , types);
7759+ if (includes & TypeIncludes.Never ) {
77537760 return neverType;
77547761 }
7755- if (typeSet.containsAny ) {
7762+ if (includes & TypeIncludes.Any ) {
77567763 return anyType;
77577764 }
7758- if (typeSet.containsEmptyObject && !typeSet.containsObjectType ) {
7765+ if (includes & TypeIncludes.EmptyObject && !(includes & TypeIncludes.ObjectType) ) {
77597766 typeSet.push(emptyObjectType);
77607767 }
77617768 if (typeSet.length === 1) {
77627769 return typeSet[0];
77637770 }
7764- const unionIndex = typeSet.unionIndex;
7765- if (unionIndex !== undefined) {
7771+ if (includes & TypeIncludes.Union) {
77667772 // We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
77677773 // the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
7774+ const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
77687775 const unionType = <UnionType>typeSet[unionIndex];
77697776 return getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
7770- UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
7777+ UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
77717778 }
77727779 const id = getTypeListId(typeSet);
77737780 let type = intersectionTypes.get(id);
0 commit comments