diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 660b19a5872..38d5ed24eae 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -274,6 +274,9 @@ namespace ts { if (isStringOrNumericLiteralLike(nameExpression)) { return escapeLeadingUnderscores(nameExpression.text); } + if (isSignedNumericLiteral(nameExpression)) { + return tokenToString(nameExpression.operator) + nameExpression.operand.text as __String; + } Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName(idText((nameExpression).name)); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7a61d9790d4..c2e6b0d518a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4652,6 +4652,9 @@ namespace ts { if (!isIdentifierText(name, compilerOptions.target) && !isNumericLiteralName(name)) { return `"${escapeString(name, CharacterCodes.doubleQuote)}"`; } + if (isNumericLiteralName(name) && startsWith(name, "-")) { + return `[${name}]`; + } return name; } if (nameType.flags & TypeFlags.UniqueESSymbol) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 75a447d6dae..562d066b64e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2705,11 +2705,19 @@ namespace ts { return isStringLiteralLike(node) || isNumericLiteral(node); } + export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpression & { operand: NumericLiteral } { + return isPrefixUnaryExpression(node) && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) && isNumericLiteral(node.operand); + } + /** - * A declaration has a dynamic name if both of the following are true: - * 1. The declaration has a computed property name - * 2. The computed name is *not* expressed as Symbol., where name - * is a property of the Symbol constructor that denotes a built in + * A declaration has a dynamic name if all of the following are true: + * 1. The declaration has a computed property name. + * 2. The computed name is *not* expressed as a StringLiteral. + * 3. The computed name is *not* expressed as a NumericLiteral. + * 4. The computed name is *not* expressed as a PlusToken or MinusToken + * immediately followed by a NumericLiteral. + * 5. The computed name is *not* expressed as `Symbol.`, where `` + * is a property of the Symbol constructor that denotes a built-in * Symbol. */ export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration { @@ -2720,6 +2728,7 @@ namespace ts { export function isDynamicName(name: DeclarationName): boolean { return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteralLike(name.expression) && + !isSignedNumericLiteral(name.expression) && !isWellKnownSymbolSyntactically(name.expression); } diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.errors.txt b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.errors.txt new file mode 100644 index 00000000000..ec8f9f5ea58 --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts(5,3): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'. + + +==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts (1 errors) ==== + var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} + ~~~~ +!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.js b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.js new file mode 100644 index 00000000000..a0a7b11fa9b --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.js @@ -0,0 +1,25 @@ +//// [computedPropertyNamesDeclarationEmit6_ES5.ts] +var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} +} + + +//// [computedPropertyNamesDeclarationEmit6_ES5.js] +var _a; +var v = (_a = {}, + _a[-1] = {}, + _a[+1] = {}, + _a[~1] = {}, + _a[!1] = {}, + _a); + + +//// [computedPropertyNamesDeclarationEmit6_ES5.d.ts] +declare var v: { + [x: number]: {}; + [-1]: {}; + 1: {}; +}; diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.symbols b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.symbols new file mode 100644 index 00000000000..40280f88d4c --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.symbols @@ -0,0 +1,17 @@ +=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts === +var v = { +>v : Symbol(v, Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 0, 3)) + + [-1]: {}, +>[-1] : Symbol([-1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 0, 9)) + + [+1]: {}, +>[+1] : Symbol([+1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 1, 11)) + + [~1]: {}, +>[~1] : Symbol([~1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 2, 11)) + + [!1]: {} +>[!1] : Symbol([!1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 3, 11)) +} + diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.types b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.types new file mode 100644 index 00000000000..ed412b8041c --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES5.types @@ -0,0 +1,30 @@ +=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts === +var v = { +>v : { [x: number]: {}; [-1]: {}; 1: {}; } +>{ [-1]: {}, [+1]: {}, [~1]: {}, [!1]: {}} : { [x: number]: {}; [-1]: {}; [+1]: {}; } + + [-1]: {}, +>[-1] : {} +>-1 : -1 +>1 : 1 +>{} : {} + + [+1]: {}, +>[+1] : {} +>+1 : 1 +>1 : 1 +>{} : {} + + [~1]: {}, +>[~1] : {} +>~1 : number +>1 : 1 +>{} : {} + + [!1]: {} +>[!1] : {} +>!1 : boolean +>1 : 1 +>{} : {} +} + diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.errors.txt b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.errors.txt new file mode 100644 index 00000000000..d5db4741dd2 --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts(5,3): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'. + + +==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts (1 errors) ==== + var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} + ~~~~ +!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.js b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.js new file mode 100644 index 00000000000..0adc9fb6de7 --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.js @@ -0,0 +1,24 @@ +//// [computedPropertyNamesDeclarationEmit6_ES6.ts] +var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} +} + + +//// [computedPropertyNamesDeclarationEmit6_ES6.js] +var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} +}; + + +//// [computedPropertyNamesDeclarationEmit6_ES6.d.ts] +declare var v: { + [x: number]: {}; + [-1]: {}; + 1: {}; +}; diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.symbols b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.symbols new file mode 100644 index 00000000000..0be9c2e9441 --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.symbols @@ -0,0 +1,17 @@ +=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts === +var v = { +>v : Symbol(v, Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 0, 3)) + + [-1]: {}, +>[-1] : Symbol([-1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 0, 9)) + + [+1]: {}, +>[+1] : Symbol([+1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 1, 11)) + + [~1]: {}, +>[~1] : Symbol([~1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 2, 11)) + + [!1]: {} +>[!1] : Symbol([!1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 3, 11)) +} + diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.types b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.types new file mode 100644 index 00000000000..d68d458621c --- /dev/null +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit6_ES6.types @@ -0,0 +1,30 @@ +=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts === +var v = { +>v : { [x: number]: {}; [-1]: {}; 1: {}; } +>{ [-1]: {}, [+1]: {}, [~1]: {}, [!1]: {}} : { [x: number]: {}; [-1]: {}; [+1]: {}; } + + [-1]: {}, +>[-1] : {} +>-1 : -1 +>1 : 1 +>{} : {} + + [+1]: {}, +>[+1] : {} +>+1 : 1 +>1 : 1 +>{} : {} + + [~1]: {}, +>[~1] : {} +>~1 : number +>1 : 1 +>{} : {} + + [!1]: {} +>[!1] : {} +>!1 : boolean +>1 : 1 +>{} : {} +} + diff --git a/tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts b/tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts new file mode 100644 index 00000000000..002ad4be296 --- /dev/null +++ b/tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts @@ -0,0 +1,8 @@ +// @target: es5 +// @declaration: true +var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} +} diff --git a/tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts b/tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts new file mode 100644 index 00000000000..b146f3de98a --- /dev/null +++ b/tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts @@ -0,0 +1,8 @@ +// @target: es6 +// @declaration: true +var v = { + [-1]: {}, + [+1]: {}, + [~1]: {}, + [!1]: {} +}