Skip to content

Commit 19a1c2c

Browse files
committed
Store actual literal value in LiteralType instances
1 parent f61efe5 commit 19a1c2c

File tree

3 files changed

+41
-35
lines changed

3 files changed

+41
-35
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,8 @@ namespace ts {
309309
let flowLoopCount = 0;
310310
let visitedFlowCount = 0;
311311

312-
const emptyStringType = getLiteralTypeForText(TypeFlags.StringLiteral, "");
313-
const zeroType = getLiteralTypeForText(TypeFlags.NumberLiteral, "0");
312+
const emptyStringType = getLiteralType("");
313+
const zeroType = getLiteralType(0);
314314

315315
const resolutionTargets: TypeSystemEntity[] = [];
316316
const resolutionResults: boolean[] = [];
@@ -1869,7 +1869,7 @@ namespace ts {
18691869
}
18701870

18711871
function createTypeofType() {
1872-
return getUnionType(convertToArray(typeofEQFacts.keys(), s => getLiteralTypeForText(TypeFlags.StringLiteral, s)));
1872+
return getUnionType(convertToArray(typeofEQFacts.keys(), getLiteralType));
18731873
}
18741874

18751875
// A reserved member name starts with two underscores, but the third character cannot be an underscore
@@ -2320,11 +2320,8 @@ namespace ts {
23202320
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
23212321
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
23222322
}
2323-
if (type.flags & (TypeFlags.StringLiteral)) {
2324-
return createLiteralTypeNode((createLiteral((<LiteralType>type).text)));
2325-
}
2326-
if (type.flags & (TypeFlags.NumberLiteral)) {
2327-
return createLiteralTypeNode((createNumericLiteral((<LiteralType>type).text)));
2323+
if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
2324+
return createLiteralTypeNode(createLiteral((<LiteralType>type).value));
23282325
}
23292326
if (type.flags & TypeFlags.BooleanLiteral) {
23302327
return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse();
@@ -2891,7 +2888,7 @@ namespace ts {
28912888
}
28922889

28932890
function literalTypeToString(type: LiteralType) {
2894-
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((<LiteralType>type).text)}"` : (<LiteralType>type).text;
2891+
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((<StringLiteralType>type).value)}"` : "" + (<NumberLiteralType>type).value;
28952892
}
28962893

28972894
function getNameOfSymbol(symbol: Symbol): string {
@@ -4933,11 +4930,11 @@ namespace ts {
49334930
return true;
49344931
}
49354932

4936-
function createEnumLiteralType(symbol: Symbol, baseType: EnumType, text: string) {
4933+
function createEnumLiteralType(symbol: Symbol, baseType: EnumType, value: number) {
49374934
const type = <EnumLiteralType>createType(TypeFlags.EnumLiteral);
49384935
type.symbol = symbol;
49394936
type.baseType = <EnumType & UnionType>baseType;
4940-
type.text = text;
4937+
type.value = value;
49414938
return type;
49424939
}
49434940

@@ -4956,7 +4953,7 @@ namespace ts {
49564953
const memberSymbol = getSymbolOfNode(member);
49574954
const value = getEnumMemberValue(member);
49584955
if (!memberTypes[value]) {
4959-
const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, "" + value);
4956+
const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, value);
49604957
memberTypeList.push(memberType);
49614958
}
49624959
}
@@ -5510,7 +5507,7 @@ namespace ts {
55105507
// If the current iteration type constituent is a string literal type, create a property.
55115508
// Otherwise, for type string create a string index signature.
55125509
if (t.flags & TypeFlags.StringLiteral) {
5513-
const propName = (<LiteralType>t).text;
5510+
const propName = (<StringLiteralType>t).value;
55145511
const modifiersProp = getPropertyOfType(modifiersType, propName);
55155512
const isOptional = templateOptional || !!(modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
55165513
const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName);
@@ -7216,7 +7213,7 @@ namespace ts {
72167213
function getLiteralTypeFromPropertyName(prop: Symbol) {
72177214
return getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier || startsWith(prop.name, "__@") ?
72187215
neverType :
7219-
getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name));
7216+
getLiteralType(unescapeIdentifier(prop.name));
72207217
}
72217218

72227219
function getLiteralTypeFromPropertyNames(type: Type) {
@@ -7253,7 +7250,7 @@ namespace ts {
72537250
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
72547251
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
72557252
const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ?
7256-
(<LiteralType>indexType).text :
7253+
"" + (<LiteralType>indexType).value :
72577254
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
72587255
getPropertyNameForKnownSymbolName((<Identifier>(<PropertyAccessExpression>accessExpression.argumentExpression).name).text) :
72597256
undefined;
@@ -7301,7 +7298,7 @@ namespace ts {
73017298
if (accessNode) {
73027299
const indexNode = accessNode.kind === SyntaxKind.ElementAccessExpression ? (<ElementAccessExpression>accessNode).argumentExpression : (<IndexedAccessTypeNode>accessNode).indexType;
73037300
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
7304-
error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, (<LiteralType>indexType).text, typeToString(objectType));
7301+
error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (<LiteralType>indexType).value, typeToString(objectType));
73057302
}
73067303
else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) {
73077304
error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType));
@@ -7512,16 +7509,16 @@ namespace ts {
75127509
return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent));
75137510
}
75147511

7515-
function createLiteralType(flags: TypeFlags, text: string) {
7512+
function createLiteralType(flags: TypeFlags, value: string | number) {
75167513
const type = <LiteralType>createType(flags);
7517-
type.text = text;
7514+
type.value = value;
75187515
return type;
75197516
}
75207517

75217518
function getFreshTypeOfLiteralType(type: Type) {
75227519
if (type.flags & TypeFlags.StringOrNumberLiteral && !(type.flags & TypeFlags.FreshLiteral)) {
75237520
if (!(<LiteralType>type).freshType) {
7524-
const freshType = <LiteralType>createLiteralType(type.flags | TypeFlags.FreshLiteral, (<LiteralType>type).text);
7521+
const freshType = <LiteralType>createLiteralType(type.flags | TypeFlags.FreshLiteral, (<LiteralType>type).value);
75257522
freshType.regularType = <LiteralType>type;
75267523
(<LiteralType>type).freshType = freshType;
75277524
}
@@ -7534,11 +7531,12 @@ namespace ts {
75347531
return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (<LiteralType>type).regularType : type;
75357532
}
75367533

7537-
function getLiteralTypeForText(flags: TypeFlags, text: string) {
7538-
const map = flags & TypeFlags.StringLiteral ? stringLiteralTypes : numericLiteralTypes;
7534+
function getLiteralType(value: string | number) {
7535+
const map = typeof value === "number" ? numericLiteralTypes : stringLiteralTypes;
7536+
const text = "" + value;
75397537
let type = map.get(text);
75407538
if (!type) {
7541-
map.set(text, type = createLiteralType(flags, text));
7539+
map.set(text, type = createLiteralType(typeof value === "number" ? TypeFlags.NumberLiteral : TypeFlags.StringLiteral, value));
75427540
}
75437541
return type;
75447542
}
@@ -8434,7 +8432,7 @@ namespace ts {
84348432
if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true;
84358433
if (source.flags & TypeFlags.EnumLiteral &&
84368434
target.flags & TypeFlags.EnumLiteral &&
8437-
(<EnumLiteralType>source).text === (<EnumLiteralType>target).text &&
8435+
(<EnumLiteralType>source).value === (<EnumLiteralType>target).value &&
84388436
isEnumTypeRelatedTo((<EnumLiteralType>source).baseType, (<EnumLiteralType>target).baseType, errorReporter)) {
84398437
return true;
84408438
}
@@ -9713,8 +9711,8 @@ namespace ts {
97139711
// no flags for all other types (including non-falsy literal types).
97149712
function getFalsyFlags(type: Type): TypeFlags {
97159713
return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((<UnionType>type).types) :
9716-
type.flags & TypeFlags.StringLiteral ? (<LiteralType>type).text === "" ? TypeFlags.StringLiteral : 0 :
9717-
type.flags & TypeFlags.NumberLiteral ? (<LiteralType>type).text === "0" ? TypeFlags.NumberLiteral : 0 :
9714+
type.flags & TypeFlags.StringLiteral ? (<LiteralType>type).value === "" ? TypeFlags.StringLiteral : 0 :
9715+
type.flags & TypeFlags.NumberLiteral ? (<LiteralType>type).value === 0 ? TypeFlags.NumberLiteral : 0 :
97189716
type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 :
97199717
type.flags & TypeFlags.PossiblyFalsy;
97209718
}
@@ -10595,14 +10593,14 @@ namespace ts {
1059510593
}
1059610594
if (flags & TypeFlags.StringLiteral) {
1059710595
return strictNullChecks ?
10598-
(<LiteralType>type).text === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts :
10599-
(<LiteralType>type).text === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts;
10596+
(<LiteralType>type).value === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts :
10597+
(<LiteralType>type).value === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts;
1060010598
}
1060110599
if (flags & (TypeFlags.Number | TypeFlags.Enum)) {
1060210600
return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts;
1060310601
}
1060410602
if (flags & (TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
10605-
const isZero = (<LiteralType>type).text === "0";
10603+
const isZero = (<LiteralType>type).value === 0;
1060610604
return strictNullChecks ?
1060710605
isZero ? TypeFacts.ZeroStrictFacts : TypeFacts.NonZeroStrictFacts :
1060810606
isZero ? TypeFacts.ZeroFacts : TypeFacts.NonZeroFacts;
@@ -13616,7 +13614,7 @@ namespace ts {
1361613614
// <CustomTag> Hello World </CustomTag>
1361713615
const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements);
1361813616
if (intrinsicElementsType !== unknownType) {
13619-
const stringLiteralTypeName = (<LiteralType>elementType).text;
13617+
const stringLiteralTypeName = (<StringLiteralType>elementType).value;
1362013618
const intrinsicProp = getPropertyOfType(intrinsicElementsType, stringLiteralTypeName);
1362113619
if (intrinsicProp) {
1362213620
return getTypeOfSymbol(intrinsicProp);
@@ -14861,7 +14859,7 @@ namespace ts {
1486114859
case SyntaxKind.Identifier:
1486214860
case SyntaxKind.NumericLiteral:
1486314861
case SyntaxKind.StringLiteral:
14864-
return getLiteralTypeForText(TypeFlags.StringLiteral, (<Identifier | LiteralExpression>element.name).text);
14862+
return getLiteralType((<Identifier | LiteralExpression>element.name).text);
1486514863

1486614864
case SyntaxKind.ComputedPropertyName:
1486714865
const nameType = checkComputedPropertyName(<ComputedPropertyName>element.name);
@@ -16345,7 +16343,7 @@ namespace ts {
1634516343
return silentNeverType;
1634616344
}
1634716345
if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) {
16348-
return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text));
16346+
return getFreshTypeOfLiteralType(getLiteralType(-(<LiteralExpression>node.operand).text));
1634916347
}
1635016348
switch (node.operator) {
1635116349
case SyntaxKind.PlusToken:
@@ -17021,9 +17019,9 @@ namespace ts {
1702117019
}
1702217020
switch (node.kind) {
1702317021
case SyntaxKind.StringLiteral:
17024-
return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text));
17022+
return getFreshTypeOfLiteralType(getLiteralType((<LiteralExpression>node).text));
1702517023
case SyntaxKind.NumericLiteral:
17026-
return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text));
17024+
return getFreshTypeOfLiteralType(getLiteralType(+(<LiteralExpression>node).text));
1702717025
case SyntaxKind.TrueKeyword:
1702817026
return trueType;
1702917027
case SyntaxKind.FalseKeyword:

src/compiler/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3036,11 +3036,19 @@ namespace ts {
30363036
// String literal types (TypeFlags.StringLiteral)
30373037
// Numeric literal types (TypeFlags.NumberLiteral)
30383038
export interface LiteralType extends Type {
3039-
text: string; // Text of literal
3039+
value: string | number; // Value of literal
30403040
freshType?: LiteralType; // Fresh version of type
30413041
regularType?: LiteralType; // Regular version of type
30423042
}
30433043

3044+
export interface StringLiteralType extends LiteralType {
3045+
value: string;
3046+
}
3047+
3048+
export interface NumberLiteralType extends LiteralType {
3049+
value: number;
3050+
}
3051+
30443052
// Enum types (TypeFlags.Enum)
30453053
export interface EnumType extends Type {
30463054
memberTypes: EnumLiteralType[];

src/services/completions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ namespace ts.Completions {
272272
}
273273
else if (type.flags & TypeFlags.StringLiteral) {
274274
result.push({
275-
name: (<LiteralType>type).text,
275+
name: (<StringLiteralType>type).value,
276276
kindModifiers: ScriptElementKindModifier.none,
277277
kind: ScriptElementKind.variableElement,
278278
sortText: "0"

0 commit comments

Comments
 (0)