Skip to content

Commit 23f1d5c

Browse files
authored
Merge pull request microsoft#32117 from andrewbranch/bug/31460
Fix declaration emit for negative number properties, allow negative numbers as computed type property names
2 parents f6d7261 + 5ff3cda commit 23f1d5c

13 files changed

+204
-4
lines changed

src/compiler/binder.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ namespace ts {
274274
if (isStringOrNumericLiteralLike(nameExpression)) {
275275
return escapeLeadingUnderscores(nameExpression.text);
276276
}
277+
if (isSignedNumericLiteral(nameExpression)) {
278+
return tokenToString(nameExpression.operator) + nameExpression.operand.text as __String;
279+
}
277280

278281
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
279282
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));

src/compiler/checker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4652,6 +4652,9 @@ namespace ts {
46524652
if (!isIdentifierText(name, compilerOptions.target) && !isNumericLiteralName(name)) {
46534653
return `"${escapeString(name, CharacterCodes.doubleQuote)}"`;
46544654
}
4655+
if (isNumericLiteralName(name) && startsWith(name, "-")) {
4656+
return `[${name}]`;
4657+
}
46554658
return name;
46564659
}
46574660
if (nameType.flags & TypeFlags.UniqueESSymbol) {

src/compiler/utilities.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,11 +2705,19 @@ namespace ts {
27052705
return isStringLiteralLike(node) || isNumericLiteral(node);
27062706
}
27072707

2708+
export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpression & { operand: NumericLiteral } {
2709+
return isPrefixUnaryExpression(node) && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) && isNumericLiteral(node.operand);
2710+
}
2711+
27082712
/**
2709-
* A declaration has a dynamic name if both of the following are true:
2710-
* 1. The declaration has a computed property name
2711-
* 2. The computed name is *not* expressed as Symbol.<name>, where name
2712-
* is a property of the Symbol constructor that denotes a built in
2713+
* A declaration has a dynamic name if all of the following are true:
2714+
* 1. The declaration has a computed property name.
2715+
* 2. The computed name is *not* expressed as a StringLiteral.
2716+
* 3. The computed name is *not* expressed as a NumericLiteral.
2717+
* 4. The computed name is *not* expressed as a PlusToken or MinusToken
2718+
* immediately followed by a NumericLiteral.
2719+
* 5. The computed name is *not* expressed as `Symbol.<name>`, where `<name>`
2720+
* is a property of the Symbol constructor that denotes a built-in
27132721
* Symbol.
27142722
*/
27152723
export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration {
@@ -2720,6 +2728,7 @@ namespace ts {
27202728
export function isDynamicName(name: DeclarationName): boolean {
27212729
return name.kind === SyntaxKind.ComputedPropertyName &&
27222730
!isStringOrNumericLiteralLike(name.expression) &&
2731+
!isSignedNumericLiteral(name.expression) &&
27232732
!isWellKnownSymbolSyntactically(name.expression);
27242733
}
27252734

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
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'.
2+
3+
4+
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts (1 errors) ====
5+
var v = {
6+
[-1]: {},
7+
[+1]: {},
8+
[~1]: {},
9+
[!1]: {}
10+
~~~~
11+
!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
12+
}
13+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [computedPropertyNamesDeclarationEmit6_ES5.ts]
2+
var v = {
3+
[-1]: {},
4+
[+1]: {},
5+
[~1]: {},
6+
[!1]: {}
7+
}
8+
9+
10+
//// [computedPropertyNamesDeclarationEmit6_ES5.js]
11+
var _a;
12+
var v = (_a = {},
13+
_a[-1] = {},
14+
_a[+1] = {},
15+
_a[~1] = {},
16+
_a[!1] = {},
17+
_a);
18+
19+
20+
//// [computedPropertyNamesDeclarationEmit6_ES5.d.ts]
21+
declare var v: {
22+
[x: number]: {};
23+
[-1]: {};
24+
1: {};
25+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts ===
2+
var v = {
3+
>v : Symbol(v, Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 0, 3))
4+
5+
[-1]: {},
6+
>[-1] : Symbol([-1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 0, 9))
7+
8+
[+1]: {},
9+
>[+1] : Symbol([+1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 1, 11))
10+
11+
[~1]: {},
12+
>[~1] : Symbol([~1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 2, 11))
13+
14+
[!1]: {}
15+
>[!1] : Symbol([!1], Decl(computedPropertyNamesDeclarationEmit6_ES5.ts, 3, 11))
16+
}
17+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES5.ts ===
2+
var v = {
3+
>v : { [x: number]: {}; [-1]: {}; 1: {}; }
4+
>{ [-1]: {}, [+1]: {}, [~1]: {}, [!1]: {}} : { [x: number]: {}; [-1]: {}; [+1]: {}; }
5+
6+
[-1]: {},
7+
>[-1] : {}
8+
>-1 : -1
9+
>1 : 1
10+
>{} : {}
11+
12+
[+1]: {},
13+
>[+1] : {}
14+
>+1 : 1
15+
>1 : 1
16+
>{} : {}
17+
18+
[~1]: {},
19+
>[~1] : {}
20+
>~1 : number
21+
>1 : 1
22+
>{} : {}
23+
24+
[!1]: {}
25+
>[!1] : {}
26+
>!1 : boolean
27+
>1 : 1
28+
>{} : {}
29+
}
30+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
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'.
2+
3+
4+
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts (1 errors) ====
5+
var v = {
6+
[-1]: {},
7+
[+1]: {},
8+
[~1]: {},
9+
[!1]: {}
10+
~~~~
11+
!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
12+
}
13+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [computedPropertyNamesDeclarationEmit6_ES6.ts]
2+
var v = {
3+
[-1]: {},
4+
[+1]: {},
5+
[~1]: {},
6+
[!1]: {}
7+
}
8+
9+
10+
//// [computedPropertyNamesDeclarationEmit6_ES6.js]
11+
var v = {
12+
[-1]: {},
13+
[+1]: {},
14+
[~1]: {},
15+
[!1]: {}
16+
};
17+
18+
19+
//// [computedPropertyNamesDeclarationEmit6_ES6.d.ts]
20+
declare var v: {
21+
[x: number]: {};
22+
[-1]: {};
23+
1: {};
24+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/es6/computedProperties/computedPropertyNamesDeclarationEmit6_ES6.ts ===
2+
var v = {
3+
>v : Symbol(v, Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 0, 3))
4+
5+
[-1]: {},
6+
>[-1] : Symbol([-1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 0, 9))
7+
8+
[+1]: {},
9+
>[+1] : Symbol([+1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 1, 11))
10+
11+
[~1]: {},
12+
>[~1] : Symbol([~1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 2, 11))
13+
14+
[!1]: {}
15+
>[!1] : Symbol([!1], Decl(computedPropertyNamesDeclarationEmit6_ES6.ts, 3, 11))
16+
}
17+

0 commit comments

Comments
 (0)