mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
Ensure enum members syntactically determinable to be strings do not get reverse mappings (#57686)
Co-authored-by: frigus02 <3579251+frigus02@users.noreply.github.com> Co-authored-by: Jan Kühle <jkuehle90@gmail.com>
This commit is contained in:
parent
ac8eb2c993
commit
f9ef9439bd
@ -122,6 +122,7 @@ import {
|
||||
isSimpleInlineableExpression,
|
||||
isSourceFile,
|
||||
isStatement,
|
||||
isSyntacticallyString,
|
||||
isTemplateLiteral,
|
||||
isTryStatement,
|
||||
JsxOpeningElement,
|
||||
@ -1922,7 +1923,7 @@ export function transformTypeScript(context: TransformationContext) {
|
||||
),
|
||||
valueExpression,
|
||||
);
|
||||
const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral ?
|
||||
const outerAssignment = isSyntacticallyString(valueExpression) ?
|
||||
innerAssignment :
|
||||
factory.createAssignment(
|
||||
factory.createElementAccessExpression(
|
||||
|
||||
@ -10638,3 +10638,22 @@ export function replaceFirstStar(s: string, replacement: string): string {
|
||||
export function getNameFromImportAttribute(node: ImportAttribute) {
|
||||
return isIdentifier(node.name) ? node.name.escapedText : escapeLeadingUnderscores(node.name.text);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isSyntacticallyString(expr: Expression): boolean {
|
||||
expr = skipOuterExpressions(expr);
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const left = (expr as BinaryExpression).left;
|
||||
const right = (expr as BinaryExpression).right;
|
||||
return (
|
||||
(expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken &&
|
||||
(isSyntacticallyString(left) || isSyntacticallyString(right))
|
||||
);
|
||||
case SyntaxKind.TemplateExpression:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -673,4 +673,13 @@ export * as alias from './file';`,
|
||||
options: { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext } },
|
||||
},
|
||||
);
|
||||
|
||||
transpilesCorrectly(
|
||||
"Syntactically string but non-evaluatable enum members do not get reverse mapping",
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
"import { BAR } from './bar'; enum Foo { A = `${BAR}` }",
|
||||
{
|
||||
options: { compilerOptions: { target: ts.ScriptTarget.ESNext } },
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
computedEnumMemberSyntacticallyString.ts(4,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(5,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(6,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(7,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(8,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
|
||||
|
||||
==== computedEnumMemberSyntacticallyString.ts (5 errors) ====
|
||||
const BAR = 2..toFixed(0);
|
||||
|
||||
enum Foo {
|
||||
A = `${BAR}`,
|
||||
~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
B = "2" + BAR,
|
||||
~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
C = (`${BAR}`),
|
||||
~~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
D = (`${BAR}}`) as string,
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
E = `${BAR}`!,
|
||||
~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
//// [tests/cases/compiler/computedEnumMemberSyntacticallyString.ts] ////
|
||||
|
||||
//// [computedEnumMemberSyntacticallyString.ts]
|
||||
const BAR = 2..toFixed(0);
|
||||
|
||||
enum Foo {
|
||||
A = `${BAR}`,
|
||||
B = "2" + BAR,
|
||||
C = (`${BAR}`),
|
||||
D = (`${BAR}}`) as string,
|
||||
E = `${BAR}`!,
|
||||
}
|
||||
|
||||
|
||||
//// [computedEnumMemberSyntacticallyString.js]
|
||||
const BAR = 2..toFixed(0);
|
||||
var Foo;
|
||||
(function (Foo) {
|
||||
Foo["A"] = `${BAR}`;
|
||||
Foo["B"] = "2" + BAR;
|
||||
Foo["C"] = (`${BAR}`);
|
||||
Foo["D"] = (`${BAR}}`);
|
||||
Foo["E"] = `${BAR}`;
|
||||
})(Foo || (Foo = {}));
|
||||
@ -0,0 +1,28 @@
|
||||
computedEnumMemberSyntacticallyString.ts(4,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(5,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(6,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(7,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
computedEnumMemberSyntacticallyString.ts(8,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
|
||||
|
||||
==== computedEnumMemberSyntacticallyString.ts (5 errors) ====
|
||||
const BAR = 2..toFixed(0);
|
||||
|
||||
enum Foo {
|
||||
A = `${BAR}`,
|
||||
~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
B = "2" + BAR,
|
||||
~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
C = (`${BAR}`),
|
||||
~~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
D = (`${BAR}}`) as string,
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
E = `${BAR}`!,
|
||||
~~~~~~~~~
|
||||
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
//// [tests/cases/compiler/computedEnumMemberSyntacticallyString.ts] ////
|
||||
|
||||
//// [computedEnumMemberSyntacticallyString.ts]
|
||||
const BAR = 2..toFixed(0);
|
||||
|
||||
enum Foo {
|
||||
A = `${BAR}`,
|
||||
B = "2" + BAR,
|
||||
C = (`${BAR}`),
|
||||
D = (`${BAR}}`) as string,
|
||||
E = `${BAR}`!,
|
||||
}
|
||||
|
||||
|
||||
//// [computedEnumMemberSyntacticallyString.js]
|
||||
const BAR = 2..toFixed(0);
|
||||
var Foo;
|
||||
(function (Foo) {
|
||||
Foo["A"] = `${BAR}`;
|
||||
Foo["B"] = "2" + BAR;
|
||||
Foo["C"] = (`${BAR}`);
|
||||
Foo["D"] = (`${BAR}}`);
|
||||
Foo["E"] = `${BAR}`;
|
||||
})(Foo || (Foo = {}));
|
||||
@ -0,0 +1,17 @@
|
||||
//// [tests/cases/compiler/computedEnumMemberSyntacticallyString2.ts] ////
|
||||
|
||||
//// [foo.ts]
|
||||
import { BAR } from './bar';
|
||||
enum Foo { A = `${BAR}` }
|
||||
|
||||
//// [bar.ts]
|
||||
export const BAR = 'bar';
|
||||
|
||||
//// [bar.js]
|
||||
export const BAR = 'bar';
|
||||
//// [foo.js]
|
||||
import { BAR } from './bar';
|
||||
var Foo;
|
||||
(function (Foo) {
|
||||
Foo["A"] = "bar";
|
||||
})(Foo || (Foo = {}));
|
||||
@ -0,0 +1,17 @@
|
||||
//// [tests/cases/compiler/computedEnumMemberSyntacticallyString2.ts] ////
|
||||
|
||||
//// [foo.ts]
|
||||
import { BAR } from './bar';
|
||||
enum Foo { A = `${BAR}` }
|
||||
|
||||
//// [bar.ts]
|
||||
export const BAR = 'bar';
|
||||
|
||||
//// [bar.js]
|
||||
export const BAR = 'bar';
|
||||
//// [foo.js]
|
||||
import { BAR } from './bar';
|
||||
var Foo;
|
||||
(function (Foo) {
|
||||
Foo["A"] = "bar";
|
||||
})(Foo || (Foo = {}));
|
||||
@ -0,0 +1,6 @@
|
||||
import { BAR } from './bar';
|
||||
var Foo;
|
||||
(function (Foo) {
|
||||
Foo["A"] = `${BAR}`;
|
||||
})(Foo || (Foo = {}));
|
||||
//# sourceMappingURL=file.js.map
|
||||
@ -0,0 +1,6 @@
|
||||
import { BAR } from './bar';
|
||||
var Foo;
|
||||
(function (Foo) {
|
||||
Foo["A"] = `${BAR}`;
|
||||
})(Foo || (Foo = {}));
|
||||
//# sourceMappingURL=file.js.map
|
||||
@ -0,0 +1,13 @@
|
||||
// @isolatedModules: true,false
|
||||
// @noTypesAndSymbols: true
|
||||
// @target: esnext
|
||||
|
||||
const BAR = 2..toFixed(0);
|
||||
|
||||
enum Foo {
|
||||
A = `${BAR}`,
|
||||
B = "2" + BAR,
|
||||
C = (`${BAR}`),
|
||||
D = (`${BAR}}`) as string,
|
||||
E = `${BAR}`!,
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
// @isolatedModules: true,false
|
||||
// @noTypesAndSymbols: true
|
||||
// @target: esnext
|
||||
|
||||
// @filename: ./foo.ts
|
||||
import { BAR } from './bar';
|
||||
enum Foo { A = `${BAR}` }
|
||||
|
||||
// @filename: ./bar.ts
|
||||
export const BAR = 'bar';
|
||||
Loading…
x
Reference in New Issue
Block a user