@@ -3838,6 +3838,14 @@ namespace ts {
38383838 return true;
38393839 }
38403840
3841+ function createEnumLiteralType(symbol: Symbol, baseType: EnumType, text: string) {
3842+ const type = <EnumLiteralType>createType(TypeFlags.EnumLiteral);
3843+ type.symbol = symbol;
3844+ type.baseType = <EnumType & UnionType>baseType;
3845+ type.text = text;
3846+ return type;
3847+ }
3848+
38413849 function getDeclaredTypeOfEnum(symbol: Symbol): Type {
38423850 const links = getSymbolLinks(symbol);
38433851 if (!links.declaredType) {
@@ -3853,10 +3861,7 @@ namespace ts {
38533861 const memberSymbol = getSymbolOfNode(member);
38543862 const value = getEnumMemberValue(member);
38553863 if (!memberTypes[value]) {
3856- const memberType = memberTypes[value] = <EnumLiteralType>createType(TypeFlags.EnumLiteral);
3857- memberType.symbol = memberSymbol;
3858- memberType.baseType = <EnumType & UnionType>enumType;
3859- memberType.text = "" + value;
3864+ const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, "" + value);
38603865 memberTypeList.push(memberType);
38613866 }
38623867 }
@@ -5335,6 +5340,7 @@ namespace ts {
53355340 containsUndefined?: boolean;
53365341 containsNull?: boolean;
53375342 containsNonWideningType?: boolean;
5343+ containsStringOrNumberLiteral?: boolean;
53385344 }
53395345
53405346 function binarySearchTypes(types: Type[], type: Type): number {
@@ -5374,6 +5380,7 @@ namespace ts {
53745380 if (!(type.flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true;
53755381 }
53765382 else if (!(type.flags & TypeFlags.Never)) {
5383+ if (type.flags & TypeFlags.StringOrNumberLiteral) typeSet.containsStringOrNumberLiteral = true;
53775384 const len = typeSet.length;
53785385 const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearchTypes(typeSet, type);
53795386 if (index < 0) {
@@ -5420,6 +5427,19 @@ namespace ts {
54205427 }
54215428 }
54225429
5430+ function removeFreshLiteralTypes(types: Type[]) {
5431+ let i = types.length;
5432+ while (i > 1) {
5433+ i--;
5434+ const t = types[i];
5435+ if (t.flags & TypeFlags.StringOrNumberLiteral && t.flags & TypeFlags.FreshLiteral) {
5436+ if (types[i - 1] === (<LiteralType>t).regularType) {
5437+ orderedRemoveItemAt(types, i);
5438+ }
5439+ }
5440+ }
5441+ }
5442+
54235443 // We sort and deduplicate the constituent types based on object identity. If the subtypeReduction
54245444 // flag is specified we also reduce the constituent type set to only include types that aren't subtypes
54255445 // of other types. Subtype reduction is expensive for large union types and is possible only when union
@@ -5442,6 +5462,9 @@ namespace ts {
54425462 if (subtypeReduction) {
54435463 removeSubtypes(typeSet);
54445464 }
5465+ else if (typeSet.containsStringOrNumberLiteral) {
5466+ removeFreshLiteralTypes(typeSet);
5467+ }
54455468 if (typeSet.length === 0) {
54465469 return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType :
54475470 typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
@@ -5549,10 +5572,21 @@ namespace ts {
55495572
55505573 function createLiteralType(flags: TypeFlags, text: string) {
55515574 const type = <LiteralType>createType(flags);
5552- type.text = text;
5575+ const freshType = <LiteralType>createType(flags | TypeFlags.FreshLiteral);
5576+ type.text = freshType.text = text;
5577+ type.freshType = freshType;
5578+ freshType.regularType = type;
55535579 return type;
55545580 }
55555581
5582+ function getFreshTypeOfLiteralType(type: Type) {
5583+ return type.flags & TypeFlags.StringOrNumberLiteral && !(type.flags & TypeFlags.FreshLiteral) ? (<LiteralType>type).freshType : type;
5584+ }
5585+
5586+ function getRegularTypeOfLiteralType(type: Type) {
5587+ return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (<LiteralType>type).regularType : type;
5588+ }
5589+
55565590 function getLiteralTypeForText(flags: TypeFlags, text: string) {
55575591 const map = flags & TypeFlags.StringLiteral ? stringLiteralTypes : numericLiteralTypes;
55585592 return map[text] || (map[text] = createLiteralType(flags, text));
@@ -5561,7 +5595,7 @@ namespace ts {
55615595 function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type {
55625596 const links = getNodeLinks(node);
55635597 if (!links.resolvedType) {
5564- links.resolvedType = checkExpression(node.literal);
5598+ links.resolvedType = getRegularTypeOfLiteralType( checkExpression(node.literal) );
55655599 }
55665600 return links.resolvedType;
55675601 }
@@ -6273,7 +6307,7 @@ namespace ts {
62736307 if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true;
62746308 if (source.flags & TypeFlags.EnumLiteral &&
62756309 target.flags & TypeFlags.EnumLiteral &&
6276- (<LiteralType >source).text === (<LiteralType >target).text &&
6310+ (<EnumLiteralType >source).text === (<EnumLiteralType >target).text &&
62776311 isEnumTypeRelatedTo((<EnumLiteralType>source).baseType, (<EnumLiteralType>target).baseType, errorReporter)) {
62786312 return true;
62796313 }
@@ -6287,6 +6321,12 @@ namespace ts {
62876321 }
62886322
62896323 function isTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
6324+ if (source.flags & TypeFlags.Literal && source.flags & TypeFlags.FreshLiteral) {
6325+ source = (<LiteralType>source).regularType;
6326+ }
6327+ if (target.flags & TypeFlags.Literal && target.flags & TypeFlags.FreshLiteral) {
6328+ target = (<LiteralType>target).regularType;
6329+ }
62906330 if (source === target || relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
62916331 return true;
62926332 }
@@ -6384,6 +6424,12 @@ namespace ts {
63846424 // Ternary.False if they are not related.
63856425 function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
63866426 let result: Ternary;
6427+ if (source.flags & TypeFlags.Literal && source.flags & TypeFlags.FreshLiteral) {
6428+ source = (<LiteralType>source).regularType;
6429+ }
6430+ if (target.flags & TypeFlags.Literal && target.flags & TypeFlags.FreshLiteral) {
6431+ target = (<LiteralType>target).regularType;
6432+ }
63876433 // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
63886434 if (source === target) return Ternary.True;
63896435
@@ -6393,7 +6439,7 @@ namespace ts {
63936439
63946440 if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
63956441
6396- if (source.flags & TypeFlags.FreshObjectLiteral ) {
6442+ if (source.flags & TypeFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral ) {
63976443 if (hasExcessProperties(<FreshObjectLiteralType>source, target, reportErrors)) {
63986444 if (reportErrors) {
63996445 reportRelationError(headMessage, source, target);
@@ -7323,8 +7369,8 @@ namespace ts {
73237369 // no flags for all other types (including non-falsy literal types).
73247370 function getFalsyFlags(type: Type): TypeFlags {
73257371 return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((<UnionType>type).types) :
7326- type.flags & TypeFlags.StringLiteral ? type === emptyStringType ? TypeFlags.StringLiteral : 0 :
7327- type.flags & TypeFlags.NumberLiteral ? type === zeroType ? TypeFlags.NumberLiteral : 0 :
7372+ type.flags & TypeFlags.StringLiteral ? (<LiteralType> type).text === "" ? TypeFlags.StringLiteral : 0 :
7373+ type.flags & TypeFlags.NumberLiteral ? (<LiteralType> type).text === "0" ? TypeFlags.NumberLiteral : 0 :
73287374 type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 :
73297375 type.flags & TypeFlags.PossiblyFalsy;
73307376 }
@@ -7391,7 +7437,7 @@ namespace ts {
73917437 * Leave signatures alone since they are not subject to the check.
73927438 */
73937439 function getRegularTypeOfObjectLiteral(type: Type): Type {
7394- if (!(type.flags & TypeFlags.FreshObjectLiteral )) {
7440+ if (!(type.flags & TypeFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral )) {
73957441 return type;
73967442 }
73977443 const regularType = (<FreshObjectLiteralType>type).regularType;
@@ -7407,7 +7453,7 @@ namespace ts {
74077453 resolved.constructSignatures,
74087454 resolved.stringIndexInfo,
74097455 resolved.numberIndexInfo);
7410- regularNew.flags = resolved.flags & ~TypeFlags.FreshObjectLiteral ;
7456+ regularNew.flags = resolved.flags & ~TypeFlags.FreshLiteral ;
74117457 (<FreshObjectLiteralType>type).regularType = regularNew;
74127458 return regularNew;
74137459 }
@@ -8109,14 +8155,14 @@ namespace ts {
81098155 }
81108156 if (flags & TypeFlags.StringLiteral) {
81118157 return strictNullChecks ?
8112- type === emptyStringType ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts :
8113- type === emptyStringType ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts;
8158+ (<LiteralType> type).text === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts :
8159+ (<LiteralType> type).text === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts;
81148160 }
81158161 if (flags & (TypeFlags.Number | TypeFlags.Enum)) {
81168162 return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts;
81178163 }
81188164 if (flags & (TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
8119- const isZero = type === zeroType || type.flags & TypeFlags.EnumLiteral && (<LiteralType>type).text === "0";
8165+ const isZero = (<LiteralType>type).text === "0";
81208166 return strictNullChecks ?
81218167 isZero ? TypeFacts.ZeroStrictFacts : TypeFacts.NonZeroStrictFacts :
81228168 isZero ? TypeFacts.ZeroFacts : TypeFacts.NonZeroFacts;
@@ -8289,7 +8335,7 @@ namespace ts {
82898335
82908336 function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) {
82918337 if (clause.kind === SyntaxKind.CaseClause) {
8292- const caseType = checkExpression((<CaseClause>clause).expression);
8338+ const caseType = getRegularTypeOfLiteralType( checkExpression((<CaseClause>clause).expression) );
82938339 return isUnitType(caseType) ? caseType : undefined;
82948340 }
82958341 return neverType;
@@ -8670,7 +8716,11 @@ namespace ts {
86708716 const narrowedType = filterType(type, t => areTypesComparable(t, valueType));
86718717 return narrowedType.flags & TypeFlags.Never ? type : narrowedType;
86728718 }
8673- return isUnitType(valueType) ? filterType(type, t => t !== valueType) : type;
8719+ if (isUnitType(valueType)) {
8720+ const regularType = getRegularTypeOfLiteralType(valueType);
8721+ return filterType(type, t => getRegularTypeOfLiteralType(t) !== regularType);
8722+ }
8723+ return type;
86748724 }
86758725
86768726 function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type {
@@ -8715,7 +8765,7 @@ namespace ts {
87158765 if (!hasDefaultClause) {
87168766 return caseType;
87178767 }
8718- const defaultType = filterType(type, t => !(isUnitType(t) && contains(switchTypes, t )));
8768+ const defaultType = filterType(type, t => !(isUnitType(t) && contains(switchTypes, getRegularTypeOfLiteralType(t) )));
87198769 return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
87208770 }
87218771
@@ -10289,7 +10339,7 @@ namespace ts {
1028910339 const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
1029010340 const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
1029110341 const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
10292- const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral ;
10342+ const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral ;
1029310343 result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0);
1029410344 if (inDestructuringPattern) {
1029510345 result.pattern = node;
@@ -13682,12 +13732,13 @@ namespace ts {
1368213732 }
1368313733 switch (node.kind) {
1368413734 case SyntaxKind.StringLiteral:
13685- return getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text);
13735+ return getFreshTypeOfLiteralType( getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text) );
1368613736 case SyntaxKind.NumericLiteral:
13687- return getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text);
13737+ return getFreshTypeOfLiteralType( getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text) );
1368813738 case SyntaxKind.TrueKeyword:
13739+ return trueType;
1368913740 case SyntaxKind.FalseKeyword:
13690- return node.kind === SyntaxKind.TrueKeyword ? trueType : falseType;
13741+ return falseType;
1369113742 }
1369213743 }
1369313744
@@ -18472,7 +18523,7 @@ namespace ts {
1847218523 if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) {
1847318524 expr = <Expression>expr.parent;
1847418525 }
18475- return checkExpression(expr);
18526+ return getRegularTypeOfLiteralType( checkExpression(expr) );
1847618527 }
1847718528
1847818529 /**
0 commit comments