@@ -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"
@@ -5516,6 +5531,8 @@ namespace ts {
55165531 sig.minArgumentCount = minArgumentCount;
55175532 sig.hasRestParameter = hasRestParameter;
55185533 sig.hasLiteralTypes = hasLiteralTypes;
5534+ sig.target = undefined;
5535+ sig.mapper = undefined;
55195536 return sig;
55205537 }
55215538
@@ -7419,21 +7436,6 @@ namespace ts {
74197436 return links.resolvedType;
74207437 }
74217438
7422- interface TypeSet extends Array<Type> {
7423- containsAny?: boolean;
7424- containsUndefined?: boolean;
7425- containsNull?: boolean;
7426- containsNever?: boolean;
7427- containsNonWideningType?: boolean;
7428- containsString?: boolean;
7429- containsNumber?: boolean;
7430- containsESSymbol?: boolean;
7431- containsLiteralOrUniqueESSymbol?: boolean;
7432- containsObjectType?: boolean;
7433- containsEmptyObject?: boolean;
7434- unionIndex?: number;
7435- }
7436-
74377439 function getTypeId(type: Type) {
74387440 return type.id;
74397441 }
@@ -7458,28 +7460,28 @@ namespace ts {
74587460 return false;
74597461 }
74607462
7461- function addTypeToUnion(typeSet: TypeSet , type: Type) {
7463+ function addTypeToUnion(typeSet: Type[], includes: TypeIncludes , type: Type) {
74627464 const flags = type.flags;
74637465 if (flags & TypeFlags.Union) {
7464- addTypesToUnion(typeSet, (<UnionType>type).types);
7466+ includes = addTypesToUnion(typeSet, includes , (<UnionType>type).types);
74657467 }
74667468 else if (flags & TypeFlags.Any) {
7467- typeSet.containsAny = true ;
7469+ includes |= TypeIncludes.Any ;
74687470 }
74697471 else if (!strictNullChecks && flags & TypeFlags.Nullable) {
7470- if (flags & TypeFlags.Undefined) typeSet.containsUndefined = true ;
7471- if (flags & TypeFlags.Null) typeSet.containsNull = true ;
7472- if (!(flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true ;
7472+ if (flags & TypeFlags.Undefined) includes |= TypeIncludes.Undefined ;
7473+ if (flags & TypeFlags.Null) includes |= TypeIncludes.Null ;
7474+ if (!(flags & TypeFlags.ContainsWideningType)) includes |= TypeIncludes.NonWideningType ;
74737475 }
74747476 else if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && isEmptyIntersectionType(<IntersectionType>type))) {
74757477 // We ignore 'never' types in unions. Likewise, we ignore intersections of unit types as they are
74767478 // another form of 'never' (in that they have an empty value domain). We could in theory turn
74777479 // intersections of unit types into 'never' upon construction, but deferring the reduction makes it
74787480 // easier to reason about their origin.
7479- if (flags & TypeFlags.String) typeSet.containsString = true ;
7480- if (flags & TypeFlags.Number) typeSet.containsNumber = true ;
7481- if (flags & TypeFlags.ESSymbol) typeSet.containsESSymbol = true ;
7482- if (flags & TypeFlags.StringOrNumberLiteralOrUnique) typeSet.containsLiteralOrUniqueESSymbol = true ;
7481+ if (flags & TypeFlags.String) includes |= TypeIncludes.String ;
7482+ if (flags & TypeFlags.Number) includes |= TypeIncludes.Number ;
7483+ if (flags & TypeFlags.ESSymbol) includes |= TypeIncludes.ESSymbol ;
7484+ if (flags & TypeFlags.StringOrNumberLiteralOrUnique) includes |= TypeIncludes.LiteralOrUniqueESSymbol ;
74837485 const len = typeSet.length;
74847486 const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues);
74857487 if (index < 0) {
@@ -7489,14 +7491,16 @@ namespace ts {
74897491 }
74907492 }
74917493 }
7494+ return includes;
74927495 }
74937496
74947497 // Add the given types to the given type set. Order is preserved, duplicates are removed,
74957498 // and nested types of the given kind are flattened into the set.
7496- function addTypesToUnion(typeSet: TypeSet, types: Type[]) {
7499+ function addTypesToUnion(typeSet: Type[], includes: TypeIncludes, types: Type[]): TypeIncludes {
74977500 for (const type of types) {
7498- addTypeToUnion(typeSet, type);
7501+ includes = addTypeToUnion(typeSet, includes , type);
74997502 }
7503+ return includes;
75007504 }
75017505
75027506 function containsIdenticalType(types: Type[], type: Type) {
@@ -7520,7 +7524,7 @@ namespace ts {
75207524 return false;
75217525 }
75227526
7523- function isSetOfLiteralsFromSameEnum(types: TypeSet ): boolean {
7527+ function isSetOfLiteralsFromSameEnum(types: Type[] ): boolean {
75247528 const first = types[0];
75257529 if (first.flags & TypeFlags.EnumLiteral) {
75267530 const firstEnum = getParentOfSymbol(first.symbol);
@@ -7536,7 +7540,7 @@ namespace ts {
75367540 return false;
75377541 }
75387542
7539- function removeSubtypes(types: TypeSet ) {
7543+ function removeSubtypes(types: Type[] ) {
75407544 if (types.length === 0 || isSetOfLiteralsFromSameEnum(types)) {
75417545 return;
75427546 }
@@ -7549,15 +7553,15 @@ namespace ts {
75497553 }
75507554 }
75517555
7552- function removeRedundantLiteralTypes(types: TypeSet ) {
7556+ function removeRedundantLiteralTypes(types: Type[], includes: TypeIncludes ) {
75537557 let i = types.length;
75547558 while (i > 0) {
75557559 i--;
75567560 const t = types[i];
75577561 const remove =
7558- t.flags & TypeFlags.StringLiteral && types.containsString ||
7559- t.flags & TypeFlags.NumberLiteral && types.containsNumber ||
7560- t.flags & TypeFlags.UniqueESSymbol && types.containsESSymbol ||
7562+ t.flags & TypeFlags.StringLiteral && includes & TypeIncludes.String ||
7563+ t.flags & TypeFlags.NumberLiteral && includes & TypeIncludes.Number ||
7564+ t.flags & TypeFlags.UniqueESSymbol && includes & TypeIncludes.ESSymbol ||
75617565 t.flags & TypeFlags.StringOrNumberLiteral && t.flags & TypeFlags.FreshLiteral && containsType(types, (<LiteralType>t).regularType);
75627566 if (remove) {
75637567 orderedRemoveItemAt(types, i);
@@ -7579,24 +7583,24 @@ namespace ts {
75797583 if (types.length === 1) {
75807584 return types[0];
75817585 }
7582- const typeSet = [] as TypeSet ;
7583- addTypesToUnion(typeSet, types);
7584- if (typeSet.containsAny ) {
7586+ const typeSet: Type [] = [] ;
7587+ const includes = addTypesToUnion(typeSet, 0 , types);
7588+ if (includes & TypeIncludes.Any ) {
75857589 return anyType;
75867590 }
75877591 switch (unionReduction) {
75887592 case UnionReduction.Literal:
7589- if (typeSet.containsLiteralOrUniqueESSymbol ) {
7590- removeRedundantLiteralTypes(typeSet);
7593+ if (includes & TypeIncludes.LiteralOrUniqueESSymbol ) {
7594+ removeRedundantLiteralTypes(typeSet, includes );
75917595 }
75927596 break;
75937597 case UnionReduction.Subtype:
75947598 removeSubtypes(typeSet);
75957599 break;
75967600 }
75977601 if (typeSet.length === 0) {
7598- return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType :
7599- typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
7602+ return includes & TypeIncludes.Null ? includes & TypeIncludes.NonWideningType ? nullType : nullWideningType :
7603+ includes & TypeIncludes.Undefined ? includes & TypeIncludes.NonWideningType ? undefinedType : undefinedWideningType :
76007604 neverType;
76017605 }
76027606 return getUnionTypeFromSortedList(typeSet, aliasSymbol, aliasTypeArguments);
@@ -7674,39 +7678,42 @@ namespace ts {
76747678 return links.resolvedType;
76757679 }
76767680
7677- function addTypeToIntersection(typeSet: TypeSet, type: Type) {
7678- if (type.flags & TypeFlags.Intersection) {
7679- addTypesToIntersection(typeSet, (<IntersectionType>type).types);
7681+ function addTypeToIntersection(typeSet: Type[], includes: TypeIncludes, type: Type) {
7682+ const flags = type.flags;
7683+ if (flags & TypeFlags.Intersection) {
7684+ includes = addTypesToIntersection(typeSet, includes, (<IntersectionType>type).types);
76807685 }
7681- else if (type. flags & TypeFlags.Any) {
7682- typeSet.containsAny = true ;
7686+ else if (flags & TypeFlags.Any) {
7687+ includes |= TypeIncludes.Any ;
76837688 }
7684- else if (type. flags & TypeFlags.Never) {
7685- typeSet.containsNever = true ;
7689+ else if (flags & TypeFlags.Never) {
7690+ includes |= TypeIncludes.Never ;
76867691 }
76877692 else if (getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type)) {
7688- typeSet.containsEmptyObject = true ;
7693+ includes |= TypeIncludes.EmptyObject ;
76897694 }
7690- else if ((strictNullChecks || !(type. flags & TypeFlags.Nullable)) && !contains(typeSet, type)) {
7691- if (type. flags & TypeFlags.Object) {
7692- typeSet.containsObjectType = true ;
7695+ else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !contains(typeSet, type)) {
7696+ if (flags & TypeFlags.Object) {
7697+ includes |= TypeIncludes.ObjectType ;
76937698 }
7694- if (type. flags & TypeFlags.Union && typeSet.unionIndex === undefined ) {
7695- typeSet.unionIndex = typeSet.length ;
7699+ if (flags & TypeFlags.Union) {
7700+ includes |= TypeIncludes.Union ;
76967701 }
7697- if (!(type. flags & TypeFlags.Object && (<ObjectType>type).objectFlags & ObjectFlags.Anonymous &&
7702+ if (!(flags & TypeFlags.Object && (<ObjectType>type).objectFlags & ObjectFlags.Anonymous &&
76987703 type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && containsIdenticalType(typeSet, type))) {
76997704 typeSet.push(type);
77007705 }
77017706 }
7707+ return includes;
77027708 }
77037709
77047710 // Add the given types to the given type set. Order is preserved, freshness is removed from literal
77057711 // types, duplicates are removed, and nested types of the given kind are flattened into the set.
7706- function addTypesToIntersection(typeSet: TypeSet , types: Type[]) {
7712+ function addTypesToIntersection(typeSet: Type[], includes: TypeIncludes , types: Type[]) {
77077713 for (const type of types) {
7708- addTypeToIntersection(typeSet, getRegularTypeOfLiteralType(type));
7714+ includes = addTypeToIntersection(typeSet, includes , getRegularTypeOfLiteralType(type));
77097715 }
7716+ return includes;
77107717 }
77117718
77127719 // We normalize combinations of intersection and union types based on the distributive property of the '&'
@@ -7723,27 +7730,27 @@ namespace ts {
77237730 if (types.length === 0) {
77247731 return emptyObjectType;
77257732 }
7726- const typeSet = [] as TypeSet ;
7727- addTypesToIntersection(typeSet, types);
7728- if (typeSet.containsNever ) {
7733+ const typeSet: Type [] = [] ;
7734+ const includes = addTypesToIntersection(typeSet, 0 , types);
7735+ if (includes & TypeIncludes.Never ) {
77297736 return neverType;
77307737 }
7731- if (typeSet.containsAny ) {
7738+ if (includes & TypeIncludes.Any ) {
77327739 return anyType;
77337740 }
7734- if (typeSet.containsEmptyObject && !typeSet.containsObjectType ) {
7741+ if (includes & TypeIncludes.EmptyObject && !(includes & TypeIncludes.ObjectType) ) {
77357742 typeSet.push(emptyObjectType);
77367743 }
77377744 if (typeSet.length === 1) {
77387745 return typeSet[0];
77397746 }
7740- const unionIndex = typeSet.unionIndex;
7741- if (unionIndex !== undefined) {
7747+ if (includes & TypeIncludes.Union) {
77427748 // We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
77437749 // the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
7750+ const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
77447751 const unionType = <UnionType>typeSet[unionIndex];
77457752 return getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
7746- UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
7753+ UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
77477754 }
77487755 const id = getTypeListId(typeSet);
77497756 let type = intersectionTypes.get(id);
0 commit comments