diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f497ba82e47a8..4d4e75d3c085d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5277,6 +5277,16 @@ namespace ts { return links.declaredType; } + function isStringConcatExpression(expr: Node): boolean { + if (expr.kind === SyntaxKind.StringLiteral) { + return true; + } + else if (expr.kind === SyntaxKind.BinaryExpression) { + return isStringConcatExpression((expr).left) && isStringConcatExpression((expr).right); + } + return false; + } + function isLiteralEnumMember(member: EnumMember) { const expr = member.initializer; if (!expr) { @@ -5291,6 +5301,8 @@ namespace ts { (expr).operand.kind === SyntaxKind.NumericLiteral; case SyntaxKind.Identifier: return nodeIsMissing(expr) || !!getSymbolOfNode(member.parent).exports.get((expr).escapedText); + case SyntaxKind.BinaryExpression: + return isStringConcatExpression(expr); default: return false; } @@ -24064,6 +24076,9 @@ namespace ts { case SyntaxKind.AsteriskAsteriskToken: return left ** right; } } + else if (typeof left === "string" && typeof right === "string" && (expr).operatorToken.kind === SyntaxKind.PlusToken) { + return left + right; + } break; case SyntaxKind.StringLiteral: return (expr).text; diff --git a/tests/baselines/reference/enumConstantMemberWithString.errors.txt b/tests/baselines/reference/enumConstantMemberWithString.errors.txt new file mode 100644 index 0000000000000..99f089e2bb3ad --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithString.errors.txt @@ -0,0 +1,45 @@ +tests/cases/conformance/enums/enumConstantMemberWithString.ts(5,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumConstantMemberWithString.ts(6,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumConstantMemberWithString.ts(18,9): error TS2553: Computed values are not permitted in an enum with string valued members. + + +==== tests/cases/conformance/enums/enumConstantMemberWithString.ts (3 errors) ==== + enum T1 { + a = "1", + b = "1" + "2", + c = "1" + "2" + "3", + d = "a" - "a", + ~~~~~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + e = "a" + 1 + ~~~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + } + + enum T2 { + a = "1", + b = "1" + "2" + } + + enum T3 { + a = "1", + b = "1" + "2", + c = 1, + d = 1 + 2 + ~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + } + + enum T4 { + a = "1" + } + + enum T5 { + a = "1" + "2" + } + + declare enum T6 { + a = "1", + b = "1" + "2" + } + \ No newline at end of file diff --git a/tests/baselines/reference/enumConstantMemberWithString.js b/tests/baselines/reference/enumConstantMemberWithString.js new file mode 100644 index 0000000000000..fc61ed484c84b --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithString.js @@ -0,0 +1,64 @@ +//// [enumConstantMemberWithString.ts] +enum T1 { + a = "1", + b = "1" + "2", + c = "1" + "2" + "3", + d = "a" - "a", + e = "a" + 1 +} + +enum T2 { + a = "1", + b = "1" + "2" +} + +enum T3 { + a = "1", + b = "1" + "2", + c = 1, + d = 1 + 2 +} + +enum T4 { + a = "1" +} + +enum T5 { + a = "1" + "2" +} + +declare enum T6 { + a = "1", + b = "1" + "2" +} + + +//// [enumConstantMemberWithString.js] +var T1; +(function (T1) { + T1["a"] = "1"; + T1["b"] = "12"; + T1["c"] = "123"; + T1[T1["d"] = 0] = "d"; + T1[T1["e"] = 0] = "e"; +})(T1 || (T1 = {})); +var T2; +(function (T2) { + T2["a"] = "1"; + T2["b"] = "12"; +})(T2 || (T2 = {})); +var T3; +(function (T3) { + T3["a"] = "1"; + T3["b"] = "12"; + T3[T3["c"] = 1] = "c"; + T3[T3["d"] = 0] = "d"; +})(T3 || (T3 = {})); +var T4; +(function (T4) { + T4["a"] = "1"; +})(T4 || (T4 = {})); +var T5; +(function (T5) { + T5["a"] = "12"; +})(T5 || (T5 = {})); diff --git a/tests/baselines/reference/enumConstantMemberWithString.symbols b/tests/baselines/reference/enumConstantMemberWithString.symbols new file mode 100644 index 0000000000000..625c24fdfefd1 --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithString.symbols @@ -0,0 +1,70 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithString.ts === +enum T1 { +>T1 : Symbol(T1, Decl(enumConstantMemberWithString.ts, 0, 0)) + + a = "1", +>a : Symbol(T1.a, Decl(enumConstantMemberWithString.ts, 0, 9)) + + b = "1" + "2", +>b : Symbol(T1.b, Decl(enumConstantMemberWithString.ts, 1, 12)) + + c = "1" + "2" + "3", +>c : Symbol(T1.c, Decl(enumConstantMemberWithString.ts, 2, 18)) + + d = "a" - "a", +>d : Symbol(T1.d, Decl(enumConstantMemberWithString.ts, 3, 24)) + + e = "a" + 1 +>e : Symbol(T1.e, Decl(enumConstantMemberWithString.ts, 4, 18)) +} + +enum T2 { +>T2 : Symbol(T2, Decl(enumConstantMemberWithString.ts, 6, 1)) + + a = "1", +>a : Symbol(T2.a, Decl(enumConstantMemberWithString.ts, 8, 9)) + + b = "1" + "2" +>b : Symbol(T2.b, Decl(enumConstantMemberWithString.ts, 9, 12)) +} + +enum T3 { +>T3 : Symbol(T3, Decl(enumConstantMemberWithString.ts, 11, 1)) + + a = "1", +>a : Symbol(T3.a, Decl(enumConstantMemberWithString.ts, 13, 9)) + + b = "1" + "2", +>b : Symbol(T3.b, Decl(enumConstantMemberWithString.ts, 14, 12)) + + c = 1, +>c : Symbol(T3.c, Decl(enumConstantMemberWithString.ts, 15, 18)) + + d = 1 + 2 +>d : Symbol(T3.d, Decl(enumConstantMemberWithString.ts, 16, 10)) +} + +enum T4 { +>T4 : Symbol(T4, Decl(enumConstantMemberWithString.ts, 18, 1)) + + a = "1" +>a : Symbol(T4.a, Decl(enumConstantMemberWithString.ts, 20, 9)) +} + +enum T5 { +>T5 : Symbol(T5, Decl(enumConstantMemberWithString.ts, 22, 1)) + + a = "1" + "2" +>a : Symbol(T5.a, Decl(enumConstantMemberWithString.ts, 24, 9)) +} + +declare enum T6 { +>T6 : Symbol(T6, Decl(enumConstantMemberWithString.ts, 26, 1)) + + a = "1", +>a : Symbol(T6.a, Decl(enumConstantMemberWithString.ts, 28, 17)) + + b = "1" + "2" +>b : Symbol(T6.b, Decl(enumConstantMemberWithString.ts, 29, 12)) +} + diff --git a/tests/baselines/reference/enumConstantMemberWithString.types b/tests/baselines/reference/enumConstantMemberWithString.types new file mode 100644 index 0000000000000..91bc2f97072f9 --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithString.types @@ -0,0 +1,105 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithString.ts === +enum T1 { +>T1 : T1 + + a = "1", +>a : T1.a +>"1" : "1" + + b = "1" + "2", +>b : T1.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" + + c = "1" + "2" + "3", +>c : T1.c +>"1" + "2" + "3" : string +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +>"3" : "3" + + d = "a" - "a", +>d : T1.d +>"a" - "a" : number +>"a" : "a" +>"a" : "a" + + e = "a" + 1 +>e : T1.d +>"a" + 1 : string +>"a" : "a" +>1 : 1 +} + +enum T2 { +>T2 : T2 + + a = "1", +>a : T2.a +>"1" : "1" + + b = "1" + "2" +>b : T2.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + +enum T3 { +>T3 : T3 + + a = "1", +>a : T3.a +>"1" : "1" + + b = "1" + "2", +>b : T3.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" + + c = 1, +>c : T3.c +>1 : 1 + + d = 1 + 2 +>d : T3.d +>1 + 2 : number +>1 : 1 +>2 : 2 +} + +enum T4 { +>T4 : T4 + + a = "1" +>a : T4 +>"1" : "1" +} + +enum T5 { +>T5 : T5 + + a = "1" + "2" +>a : T5 +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + +declare enum T6 { +>T6 : T6 + + a = "1", +>a : T6.a +>"1" : "1" + + b = "1" + "2" +>b : T6.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + diff --git a/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.js b/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.js new file mode 100644 index 0000000000000..d78ce824256d8 --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.js @@ -0,0 +1,82 @@ +//// [enumConstantMemberWithStringEmitDeclaration.ts] +enum T1 { + a = "1", + b = "1" + "2", + c = "1" + "2" + "3" +} + +enum T2 { + a = "1", + b = "1" + "2" +} + +enum T3 { + a = "1", + b = "1" + "2" +} + +enum T4 { + a = "1" +} + +enum T5 { + a = "1" + "2" +} + +declare enum T6 { + a = "1", + b = "1" + "2" +} + + +//// [enumConstantMemberWithStringEmitDeclaration.js] +var T1; +(function (T1) { + T1["a"] = "1"; + T1["b"] = "12"; + T1["c"] = "123"; +})(T1 || (T1 = {})); +var T2; +(function (T2) { + T2["a"] = "1"; + T2["b"] = "12"; +})(T2 || (T2 = {})); +var T3; +(function (T3) { + T3["a"] = "1"; + T3["b"] = "12"; +})(T3 || (T3 = {})); +var T4; +(function (T4) { + T4["a"] = "1"; +})(T4 || (T4 = {})); +var T5; +(function (T5) { + T5["a"] = "12"; +})(T5 || (T5 = {})); + + +//// [enumConstantMemberWithStringEmitDeclaration.d.ts] +declare enum T1 { + a = "1", + b = "12", + c = "123" +} +declare enum T2 { + a = "1", + b = "12" +} +declare enum T3 { + a = "1", + b = "12" +} +declare enum T4 { + a = "1" +} +declare enum T5 { + a = "12" +} +declare enum T6 { + a = "1", + b = "12" +} diff --git a/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.symbols b/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.symbols new file mode 100644 index 0000000000000..1bb70c7882b2d --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.symbols @@ -0,0 +1,58 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithStringEmitDeclaration.ts === +enum T1 { +>T1 : Symbol(T1, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 0, 0)) + + a = "1", +>a : Symbol(T1.a, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 0, 9)) + + b = "1" + "2", +>b : Symbol(T1.b, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 1, 12)) + + c = "1" + "2" + "3" +>c : Symbol(T1.c, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 2, 18)) +} + +enum T2 { +>T2 : Symbol(T2, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 4, 1)) + + a = "1", +>a : Symbol(T2.a, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 6, 9)) + + b = "1" + "2" +>b : Symbol(T2.b, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 7, 12)) +} + +enum T3 { +>T3 : Symbol(T3, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 9, 1)) + + a = "1", +>a : Symbol(T3.a, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 11, 9)) + + b = "1" + "2" +>b : Symbol(T3.b, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 12, 12)) +} + +enum T4 { +>T4 : Symbol(T4, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 14, 1)) + + a = "1" +>a : Symbol(T4.a, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 16, 9)) +} + +enum T5 { +>T5 : Symbol(T5, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 18, 1)) + + a = "1" + "2" +>a : Symbol(T5.a, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 20, 9)) +} + +declare enum T6 { +>T6 : Symbol(T6, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 22, 1)) + + a = "1", +>a : Symbol(T6.a, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 24, 17)) + + b = "1" + "2" +>b : Symbol(T6.b, Decl(enumConstantMemberWithStringEmitDeclaration.ts, 25, 12)) +} + diff --git a/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.types b/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.types new file mode 100644 index 0000000000000..b613ec306e47c --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithStringEmitDeclaration.types @@ -0,0 +1,83 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithStringEmitDeclaration.ts === +enum T1 { +>T1 : T1 + + a = "1", +>a : T1.a +>"1" : "1" + + b = "1" + "2", +>b : T1.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" + + c = "1" + "2" + "3" +>c : T1.c +>"1" + "2" + "3" : string +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +>"3" : "3" +} + +enum T2 { +>T2 : T2 + + a = "1", +>a : T2.a +>"1" : "1" + + b = "1" + "2" +>b : T2.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + +enum T3 { +>T3 : T3 + + a = "1", +>a : T3.a +>"1" : "1" + + b = "1" + "2" +>b : T3.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + +enum T4 { +>T4 : T4 + + a = "1" +>a : T4 +>"1" : "1" +} + +enum T5 { +>T5 : T5 + + a = "1" + "2" +>a : T5 +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + +declare enum T6 { +>T6 : T6 + + a = "1", +>a : T6.a +>"1" : "1" + + b = "1" + "2" +>b : T6.b +>"1" + "2" : string +>"1" : "1" +>"2" : "2" +} + diff --git a/tests/cases/conformance/enums/enumConstantMemberWithString.ts b/tests/cases/conformance/enums/enumConstantMemberWithString.ts new file mode 100644 index 0000000000000..0d2e3a207e2a3 --- /dev/null +++ b/tests/cases/conformance/enums/enumConstantMemberWithString.ts @@ -0,0 +1,32 @@ +enum T1 { + a = "1", + b = "1" + "2", + c = "1" + "2" + "3", + d = "a" - "a", + e = "a" + 1 +} + +enum T2 { + a = "1", + b = "1" + "2" +} + +enum T3 { + a = "1", + b = "1" + "2", + c = 1, + d = 1 + 2 +} + +enum T4 { + a = "1" +} + +enum T5 { + a = "1" + "2" +} + +declare enum T6 { + a = "1", + b = "1" + "2" +} diff --git a/tests/cases/conformance/enums/enumConstantMemberWithStringEmitDeclaration.ts b/tests/cases/conformance/enums/enumConstantMemberWithStringEmitDeclaration.ts new file mode 100644 index 0000000000000..37667dca79c9c --- /dev/null +++ b/tests/cases/conformance/enums/enumConstantMemberWithStringEmitDeclaration.ts @@ -0,0 +1,29 @@ +// @declaration: true +enum T1 { + a = "1", + b = "1" + "2", + c = "1" + "2" + "3" +} + +enum T2 { + a = "1", + b = "1" + "2" +} + +enum T3 { + a = "1", + b = "1" + "2" +} + +enum T4 { + a = "1" +} + +enum T5 { + a = "1" + "2" +} + +declare enum T6 { + a = "1", + b = "1" + "2" +}