Skip to content

Commit 76fe6a3

Browse files
committed
feat(40793): allow constants/template literals as enum values
1 parent cdc1996 commit 76fe6a3

File tree

5 files changed

+167
-0
lines changed

5 files changed

+167
-0
lines changed

src/compiler/checker.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40609,6 +40609,17 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
4060940609
}
4061040610
}
4061140611
break;
40612+
case SyntaxKind.TemplateExpression:
40613+
const expression = expr as TemplateExpression;
40614+
const texts = [expression.head.text];
40615+
for (const span of expression.templateSpans) {
40616+
const exprValue = evaluate(span.expression);
40617+
if (exprValue === undefined) return undefined;
40618+
40619+
texts.push(exprValue + "");
40620+
texts.push(span.literal.text);
40621+
}
40622+
return texts.join("");
4061240623
}
4061340624
return undefined;
4061440625
}
@@ -40625,9 +40636,36 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
4062540636
return 0;
4062640637
}
4062740638
else {
40639+
const exprValue = evaluateExpression(expr);
40640+
if (exprValue) return exprValue;
4062840641
error(expr, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(memberSymbol));
4062940642
}
4063040643
}
40644+
return evaluateExpression(expr);
40645+
}
40646+
40647+
function evaluateExpression(expr: Expression) {
40648+
if (isIdentifier(expr)) {
40649+
const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, getSourceFileOfNode(expr));
40650+
if (!symbol || !isConstVariable(symbol)) return undefined;
40651+
40652+
const declaration = symbol.valueDeclaration;
40653+
if (declaration === undefined) return undefined;
40654+
40655+
if (isBlockScopedNameDeclaredBeforeUse(declaration, member) && hasOnlyExpressionInitializer(declaration)) {
40656+
const initializer = getEffectiveInitializer(declaration);
40657+
if (initializer === undefined) return undefined;
40658+
40659+
if (isTemplateExpression(initializer)) {
40660+
return evaluate(initializer);
40661+
}
40662+
40663+
const type = getTypeOfExpression(initializer);
40664+
if (type.flags & TypeFlags.StringOrNumberLiteral) {
40665+
return (type as NumberLiteralType | StringLiteralType).value;
40666+
}
40667+
}
40668+
}
4063140669
return undefined;
4063240670
}
4063340671
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [enumWithConst.ts]
2+
const A = 1;
3+
const B = "B";
4+
const C: string = "C";
5+
const D = `D_${A}_${B}_${C}`;
6+
7+
enum T {
8+
A = A,
9+
B = B,
10+
C = C,
11+
D = D,
12+
E = `E_${A}_${B}_${C}`
13+
}
14+
15+
16+
//// [enumWithConst.js]
17+
var A = 1;
18+
var B = "B";
19+
var C = "C";
20+
var D = "D_".concat(A, "_").concat(B, "_").concat(C);
21+
var T;
22+
(function (T) {
23+
T[T["A"] = 1] = "A";
24+
T["B"] = "B";
25+
T["C"] = "C";
26+
T["D"] = "D_1_B_C";
27+
T["E"] = "E_1_B_C";
28+
})(T || (T = {}));
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
=== tests/cases/compiler/enumWithConst.ts ===
2+
const A = 1;
3+
>A : Symbol(A, Decl(enumWithConst.ts, 0, 5))
4+
5+
const B = "B";
6+
>B : Symbol(B, Decl(enumWithConst.ts, 1, 5))
7+
8+
const C: string = "C";
9+
>C : Symbol(C, Decl(enumWithConst.ts, 2, 5))
10+
11+
const D = `D_${A}_${B}_${C}`;
12+
>D : Symbol(D, Decl(enumWithConst.ts, 3, 5))
13+
>A : Symbol(A, Decl(enumWithConst.ts, 0, 5))
14+
>B : Symbol(B, Decl(enumWithConst.ts, 1, 5))
15+
>C : Symbol(C, Decl(enumWithConst.ts, 2, 5))
16+
17+
enum T {
18+
>T : Symbol(T, Decl(enumWithConst.ts, 3, 29))
19+
20+
A = A,
21+
>A : Symbol(T.A, Decl(enumWithConst.ts, 5, 8))
22+
>A : Symbol(T.A, Decl(enumWithConst.ts, 5, 8))
23+
24+
B = B,
25+
>B : Symbol(T.B, Decl(enumWithConst.ts, 6, 10))
26+
>B : Symbol(T.B, Decl(enumWithConst.ts, 6, 10))
27+
28+
C = C,
29+
>C : Symbol(T.C, Decl(enumWithConst.ts, 7, 10))
30+
>C : Symbol(T.C, Decl(enumWithConst.ts, 7, 10))
31+
32+
D = D,
33+
>D : Symbol(T.D, Decl(enumWithConst.ts, 8, 10))
34+
>D : Symbol(T.D, Decl(enumWithConst.ts, 8, 10))
35+
36+
E = `E_${A}_${B}_${C}`
37+
>E : Symbol(T.E, Decl(enumWithConst.ts, 9, 10))
38+
>A : Symbol(T.A, Decl(enumWithConst.ts, 5, 8))
39+
>B : Symbol(T.B, Decl(enumWithConst.ts, 6, 10))
40+
>C : Symbol(T.C, Decl(enumWithConst.ts, 7, 10))
41+
}
42+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
=== tests/cases/compiler/enumWithConst.ts ===
2+
const A = 1;
3+
>A : 1
4+
>1 : 1
5+
6+
const B = "B";
7+
>B : "B"
8+
>"B" : "B"
9+
10+
const C: string = "C";
11+
>C : string
12+
>"C" : "C"
13+
14+
const D = `D_${A}_${B}_${C}`;
15+
>D : string
16+
>`D_${A}_${B}_${C}` : string
17+
>A : 1
18+
>B : "B"
19+
>C : string
20+
21+
enum T {
22+
>T : T
23+
24+
A = A,
25+
>A : T
26+
>A : T
27+
28+
B = B,
29+
>B : T
30+
>B : T
31+
32+
C = C,
33+
>C : T
34+
>C : T
35+
36+
D = D,
37+
>D : T
38+
>D : T
39+
40+
E = `E_${A}_${B}_${C}`
41+
>E : T
42+
>`E_${A}_${B}_${C}` : string
43+
>A : T
44+
>B : T
45+
>C : T
46+
}
47+

tests/cases/compiler/enumWithConst.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const A = 1;
2+
const B = "B";
3+
const C: string = "C";
4+
const D = `D_${A}_${B}_${C}`;
5+
6+
enum T {
7+
A = A,
8+
B = B,
9+
C = C,
10+
D = D,
11+
E = `E_${A}_${B}_${C}`
12+
}

0 commit comments

Comments
 (0)