Skip to content

Commit 525748e

Browse files
committed
Support template literals in const enum access
1 parent 49a11d3 commit 525748e

17 files changed

+437
-200
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20957,8 +20957,8 @@ namespace ts {
2095720957
return objectType;
2095820958
}
2095920959

20960-
if (isConstEnumObjectType(objectType) && indexExpression.kind !== SyntaxKind.StringLiteral) {
20961-
error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal);
20960+
if (isConstEnumObjectType(objectType) && !isStringLiteralLike(indexExpression)) {
20961+
error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal_or_a_template_literal);
2096220962
return errorType;
2096320963
}
2096420964

@@ -29604,7 +29604,7 @@ namespace ts {
2960429604
return node.kind === SyntaxKind.Identifier ||
2960529605
node.kind === SyntaxKind.PropertyAccessExpression && isConstantMemberAccess((<PropertyAccessExpression>node).expression) ||
2960629606
node.kind === SyntaxKind.ElementAccessExpression && isConstantMemberAccess((<ElementAccessExpression>node).expression) &&
29607-
(<ElementAccessExpression>node).argumentExpression.kind === SyntaxKind.StringLiteral;
29607+
isStringLiteralLike((<ElementAccessExpression>node).argumentExpression);
2960829608
}
2960929609

2961029610
function checkEnumDeclaration(node: EnumDeclaration) {

src/compiler/diagnosticMessages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1720,7 +1720,7 @@
17201720
"category": "Error",
17211721
"code": 2475
17221722
},
1723-
"A const enum member can only be accessed using a string literal.": {
1723+
"A const enum member can only be accessed using a string literal or a template literal.": {
17241724
"category": "Error",
17251725
"code": 2476
17261726
},

src/compiler/transformers/ts.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3246,9 +3246,10 @@ namespace ts {
32463246

32473247
const substitute = createLiteral(constantValue);
32483248
if (!compilerOptions.removeComments) {
3249-
const propertyName = isPropertyAccessExpression(node)
3250-
? declarationNameToString(node.name)
3251-
: getTextOfNode(node.argumentExpression);
3249+
const originalNode = getOriginalNode(node, isAccessExpression);
3250+
const propertyName = isPropertyAccessExpression(originalNode)
3251+
? declarationNameToString(originalNode.name)
3252+
: getTextOfNode(originalNode.argumentExpression);
32523253

32533254
addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${propertyName} `);
32543255
}

tests/baselines/reference/constEnumErrors.errors.txt

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ tests/cases/compiler/constEnumErrors.ts(5,8): error TS2567: Enum declarations ca
33
tests/cases/compiler/constEnumErrors.ts(12,9): error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.
44
tests/cases/compiler/constEnumErrors.ts(14,9): error TS2474: const enum member initializers can only contain literal values and other computed enum values.
55
tests/cases/compiler/constEnumErrors.ts(15,10): error TS2474: const enum member initializers can only contain literal values and other computed enum values.
6-
tests/cases/compiler/constEnumErrors.ts(22,13): error TS2476: A const enum member can only be accessed using a string literal.
7-
tests/cases/compiler/constEnumErrors.ts(24,13): error TS2476: A const enum member can only be accessed using a string literal.
8-
tests/cases/compiler/constEnumErrors.ts(26,9): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
9-
tests/cases/compiler/constEnumErrors.ts(27,10): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
10-
tests/cases/compiler/constEnumErrors.ts(32,5): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
11-
tests/cases/compiler/constEnumErrors.ts(40,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value.
6+
tests/cases/compiler/constEnumErrors.ts(22,13): error TS2476: A const enum member can only be accessed using a string literal or a template literal.
7+
tests/cases/compiler/constEnumErrors.ts(24,13): error TS2476: A const enum member can only be accessed using a string literal or a template literal.
8+
tests/cases/compiler/constEnumErrors.ts(25,13): error TS2476: A const enum member can only be accessed using a string literal or a template literal.
9+
tests/cases/compiler/constEnumErrors.ts(27,9): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
10+
tests/cases/compiler/constEnumErrors.ts(28,10): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
11+
tests/cases/compiler/constEnumErrors.ts(33,5): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
1212
tests/cases/compiler/constEnumErrors.ts(41,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value.
13-
tests/cases/compiler/constEnumErrors.ts(42,9): error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'.
13+
tests/cases/compiler/constEnumErrors.ts(42,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value.
14+
tests/cases/compiler/constEnumErrors.ts(43,9): error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'.
1415

1516

16-
==== tests/cases/compiler/constEnumErrors.ts (13 errors) ====
17+
==== tests/cases/compiler/constEnumErrors.ts (14 errors) ====
1718
const enum E {
1819
~
1920
!!! error TS2567: Enum declarations can only merge with namespace or other enum declarations.
@@ -29,7 +30,7 @@ tests/cases/compiler/constEnumErrors.ts(42,9): error TS2478: 'const' enum member
2930
const enum E1 {
3031
// illegal case
3132
// forward reference to the element of the same enum
32-
X = Y,
33+
X = Y,
3334
~
3435
!!! error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.
3536
// forward reference to the element of the same enum
@@ -47,11 +48,14 @@ tests/cases/compiler/constEnumErrors.ts(42,9): error TS2478: 'const' enum member
4748

4849
var y0 = E2[1]
4950
~
50-
!!! error TS2476: A const enum member can only be accessed using a string literal.
51+
!!! error TS2476: A const enum member can only be accessed using a string literal or a template literal.
5152
var name = "A";
5253
var y1 = E2[name];
5354
~~~~
54-
!!! error TS2476: A const enum member can only be accessed using a string literal.
55+
!!! error TS2476: A const enum member can only be accessed using a string literal or a template literal.
56+
var y2 = E2[`${name}`];
57+
~~~~~~~~~
58+
!!! error TS2476: A const enum member can only be accessed using a string literal or a template literal.
5559

5660
var x = E2;
5761
~~

tests/baselines/reference/constEnumErrors.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module E {
1010
const enum E1 {
1111
// illegal case
1212
// forward reference to the element of the same enum
13-
X = Y,
13+
X = Y,
1414
// forward reference to the element of the same enum
1515
Y = E1.Z,
1616
Y1 = E1["Z"]
@@ -23,6 +23,7 @@ const enum E2 {
2323
var y0 = E2[1]
2424
var name = "A";
2525
var y1 = E2[name];
26+
var y2 = E2[`${name}`];
2627

2728
var x = E2;
2829
var y = [E2];
@@ -51,6 +52,7 @@ var E;
5152
var y0 = E2[1];
5253
var name = "A";
5354
var y1 = E2[name];
55+
var y2 = E2["" + name];
5456
var x = E2;
5557
var y = [E2];
5658
function foo(t) {

tests/baselines/reference/constEnumErrors.symbols

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const enum E1 {
1818

1919
// illegal case
2020
// forward reference to the element of the same enum
21-
X = Y,
21+
X = Y,
2222
>X : Symbol(E1.X, Decl(constEnumErrors.ts, 8, 15))
2323
>Y : Symbol(E1.Y, Decl(constEnumErrors.ts, 11, 10))
2424

@@ -51,57 +51,62 @@ var y1 = E2[name];
5151
>E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1))
5252
>name : Symbol(name, Decl(constEnumErrors.ts, 22, 3))
5353

54+
var y2 = E2[`${name}`];
55+
>y2 : Symbol(y2, Decl(constEnumErrors.ts, 24, 3))
56+
>E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1))
57+
>name : Symbol(name, Decl(constEnumErrors.ts, 22, 3))
58+
5459
var x = E2;
55-
>x : Symbol(x, Decl(constEnumErrors.ts, 25, 3))
60+
>x : Symbol(x, Decl(constEnumErrors.ts, 26, 3))
5661
>E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1))
5762

5863
var y = [E2];
59-
>y : Symbol(y, Decl(constEnumErrors.ts, 26, 3))
64+
>y : Symbol(y, Decl(constEnumErrors.ts, 27, 3))
6065
>E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1))
6166

6267
function foo(t: any): void {
63-
>foo : Symbol(foo, Decl(constEnumErrors.ts, 26, 13))
64-
>t : Symbol(t, Decl(constEnumErrors.ts, 28, 13))
68+
>foo : Symbol(foo, Decl(constEnumErrors.ts, 27, 13))
69+
>t : Symbol(t, Decl(constEnumErrors.ts, 29, 13))
6570
}
6671

6772
foo(E2);
68-
>foo : Symbol(foo, Decl(constEnumErrors.ts, 26, 13))
73+
>foo : Symbol(foo, Decl(constEnumErrors.ts, 27, 13))
6974
>E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1))
7075

7176
const enum NaNOrInfinity {
72-
>NaNOrInfinity : Symbol(NaNOrInfinity, Decl(constEnumErrors.ts, 31, 8))
77+
>NaNOrInfinity : Symbol(NaNOrInfinity, Decl(constEnumErrors.ts, 32, 8))
7378

7479
A = 9007199254740992,
75-
>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 33, 26))
80+
>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 34, 26))
7681

7782
B = A * A,
78-
>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 34, 25))
79-
>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 33, 26))
80-
>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 33, 26))
83+
>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 35, 25))
84+
>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 34, 26))
85+
>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 34, 26))
8186

8287
C = B * B,
83-
>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 35, 14))
84-
>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 34, 25))
85-
>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 34, 25))
88+
>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 36, 14))
89+
>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 35, 25))
90+
>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 35, 25))
8691

8792
D = C * C,
88-
>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 36, 14))
89-
>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 35, 14))
90-
>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 35, 14))
93+
>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 37, 14))
94+
>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 36, 14))
95+
>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 36, 14))
9196

9297
E = D * D,
93-
>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 37, 14))
94-
>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 36, 14))
95-
>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 36, 14))
98+
>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 38, 14))
99+
>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 37, 14))
100+
>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 37, 14))
96101

97102
F = E * E, // overflow
98-
>F : Symbol(NaNOrInfinity.F, Decl(constEnumErrors.ts, 38, 14))
99-
>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 37, 14))
100-
>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 37, 14))
103+
>F : Symbol(NaNOrInfinity.F, Decl(constEnumErrors.ts, 39, 14))
104+
>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 38, 14))
105+
>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 38, 14))
101106

102107
G = 1 / 0, // overflow
103-
>G : Symbol(NaNOrInfinity.G, Decl(constEnumErrors.ts, 39, 14))
108+
>G : Symbol(NaNOrInfinity.G, Decl(constEnumErrors.ts, 40, 14))
104109

105110
H = 0 / 0 // NaN
106-
>H : Symbol(NaNOrInfinity.H, Decl(constEnumErrors.ts, 40, 14))
111+
>H : Symbol(NaNOrInfinity.H, Decl(constEnumErrors.ts, 41, 14))
107112
}

tests/baselines/reference/constEnumErrors.types

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const enum E1 {
1919

2020
// illegal case
2121
// forward reference to the element of the same enum
22-
X = Y,
22+
X = Y,
2323
>X : E1
2424
>Y : E1
2525

@@ -60,6 +60,13 @@ var y1 = E2[name];
6060
>E2 : typeof E2
6161
>name : string
6262

63+
var y2 = E2[`${name}`];
64+
>y2 : any
65+
>E2[`${name}`] : any
66+
>E2 : typeof E2
67+
>`${name}` : string
68+
>name : string
69+
6370
var x = E2;
6471
>x : typeof E2
6572
>E2 : typeof E2

tests/baselines/reference/constEnumPropertyAccess2.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
tests/cases/conformance/constEnums/constEnumPropertyAccess2.ts(13,9): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
2-
tests/cases/conformance/constEnums/constEnumPropertyAccess2.ts(14,12): error TS2476: A const enum member can only be accessed using a string literal.
2+
tests/cases/conformance/constEnums/constEnumPropertyAccess2.ts(14,12): error TS2476: A const enum member can only be accessed using a string literal or a template literal.
33
tests/cases/conformance/constEnums/constEnumPropertyAccess2.ts(16,1): error TS2322: Type '"string"' is not assignable to type 'G'.
44
tests/cases/conformance/constEnums/constEnumPropertyAccess2.ts(18,3): error TS2540: Cannot assign to 'B' because it is a read-only property.
55

@@ -22,7 +22,7 @@ tests/cases/conformance/constEnums/constEnumPropertyAccess2.ts(18,3): error TS25
2222
!!! error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
2323
var z1 = G[G.A];
2424
~~~
25-
!!! error TS2476: A const enum member can only be accessed using a string literal.
25+
!!! error TS2476: A const enum member can only be accessed using a string literal or a template literal.
2626
var g: G;
2727
g = "string";
2828
~
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [constEnumSyntheticNodesComments.ts]
2+
const enum En { A, B, C, D }
3+
4+
function assert<T>(x: T) {
5+
return x;
6+
}
7+
8+
function verify(a: En) {
9+
switch (a) {
10+
case En.A:
11+
return assert<0>(a);
12+
case En["B"]:
13+
return assert<1>(a);
14+
case En[`C`]:
15+
return assert<2>(a);
16+
case En["\u{44}"]:
17+
return assert<3>(a);
18+
}
19+
}
20+
21+
//// [constEnumSyntheticNodesComments.js]
22+
function assert(x) {
23+
return x;
24+
}
25+
function verify(a) {
26+
switch (a) {
27+
case 0 /* A */:
28+
return assert(a);
29+
case 1 /* "B" */:
30+
return assert(a);
31+
case 2 /* `C` */:
32+
return assert(a);
33+
case 3 /* "\u{44}" */:
34+
return assert(a);
35+
}
36+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
=== tests/cases/compiler/constEnumSyntheticNodesComments.ts ===
2+
const enum En { A, B, C, D }
3+
>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0))
4+
>A : Symbol(En.A, Decl(constEnumSyntheticNodesComments.ts, 0, 15))
5+
>B : Symbol(En.B, Decl(constEnumSyntheticNodesComments.ts, 0, 18))
6+
>C : Symbol(En.C, Decl(constEnumSyntheticNodesComments.ts, 0, 21))
7+
>D : Symbol(En.D, Decl(constEnumSyntheticNodesComments.ts, 0, 24))
8+
9+
function assert<T>(x: T) {
10+
>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28))
11+
>T : Symbol(T, Decl(constEnumSyntheticNodesComments.ts, 2, 16))
12+
>x : Symbol(x, Decl(constEnumSyntheticNodesComments.ts, 2, 19))
13+
>T : Symbol(T, Decl(constEnumSyntheticNodesComments.ts, 2, 16))
14+
15+
return x;
16+
>x : Symbol(x, Decl(constEnumSyntheticNodesComments.ts, 2, 19))
17+
}
18+
19+
function verify(a: En) {
20+
>verify : Symbol(verify, Decl(constEnumSyntheticNodesComments.ts, 4, 1))
21+
>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16))
22+
>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0))
23+
24+
switch (a) {
25+
>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16))
26+
27+
case En.A:
28+
>En.A : Symbol(En.A, Decl(constEnumSyntheticNodesComments.ts, 0, 15))
29+
>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0))
30+
>A : Symbol(En.A, Decl(constEnumSyntheticNodesComments.ts, 0, 15))
31+
32+
return assert<0>(a);
33+
>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28))
34+
>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16))
35+
36+
case En["B"]:
37+
>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0))
38+
>"B" : Symbol(En.B, Decl(constEnumSyntheticNodesComments.ts, 0, 18))
39+
40+
return assert<1>(a);
41+
>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28))
42+
>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16))
43+
44+
case En[`C`]:
45+
>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0))
46+
>`C` : Symbol(En.C, Decl(constEnumSyntheticNodesComments.ts, 0, 21))
47+
48+
return assert<2>(a);
49+
>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28))
50+
>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16))
51+
52+
case En["\u{44}"]:
53+
>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0))
54+
>"\u{44}" : Symbol(En.D, Decl(constEnumSyntheticNodesComments.ts, 0, 24))
55+
56+
return assert<3>(a);
57+
>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28))
58+
>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16))
59+
}
60+
}

0 commit comments

Comments
 (0)