Skip to content

Commit 57674dd

Browse files
committed
Emit dynamic names for object literal types
1 parent 64fd857 commit 57674dd

12 files changed

+90
-75
lines changed

src/compiler/checker.ts

+19-6
Original file line numberDiff line numberDiff line change
@@ -2897,9 +2897,6 @@ namespace ts {
28972897
}
28982898

28992899
function getNameOfSymbol(symbol: Symbol): string {
2900-
if (symbol.flags & SymbolFlags.Dynamic) {
2901-
return `"${escapeString(unescapeIdentifier(symbol.name))}"`;
2902-
}
29032900
if (symbol.declarations && symbol.declarations.length) {
29042901
const declaration = symbol.declarations[0];
29052902
if (declaration.name) {
@@ -3258,6 +3255,9 @@ namespace ts {
32583255
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
32593256
writeSpace(writer);
32603257
}
3258+
if (prop.flags & SymbolFlags.Dynamic && (<TransientSymbol>prop).dynamicSource) {
3259+
writer.trackSymbol((<TransientSymbol>prop).dynamicSource, enclosingDeclaration, SymbolFlags.Value);
3260+
}
32613261
buildSymbolDisplay(prop, writer);
32623262
if (prop.flags & SymbolFlags.Optional) {
32633263
writePunctuation(writer, SyntaxKind.QuestionToken);
@@ -5193,7 +5193,7 @@ namespace ts {
51935193
resolveDynamicMembersOfNode(node, (<ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode>node).members, symbolTable);
51945194
break;
51955195
case SyntaxKind.ObjectLiteralExpression:
5196-
resolveDynamicMembersOfNode(node, (<ObjectLiteralExpression>node).properties, symbolTable);
5196+
resolveDynamicMembersOfNode(node, (<ObjectLiteralExpression>node).properties, symbolTable);
51975197
break;
51985198
}
51995199
}
@@ -13191,7 +13191,20 @@ namespace ts {
1319113191
}
1319213192

1319313193
typeFlags |= type.flags;
13194-
const prop = createSymbol(SymbolFlags.Property | member.flags, member.name);
13194+
13195+
let prop: TransientSymbol;
13196+
if (hasDynamicName(memberDecl) && isEntityNameExpression((<ComputedPropertyName>memberDecl.name).expression)) {
13197+
const nameType = checkComputedPropertyName(<ComputedPropertyName>memberDecl.name);
13198+
if (nameType && nameType.flags & TypeFlags.StringOrNumberLiteral) {
13199+
prop = createSymbol(SymbolFlags.Property | SymbolFlags.Dynamic | member.flags, (<LiteralType>nameType).text);
13200+
prop.dynamicSource = resolveEntityName(<EntityNameExpression>(<ComputedPropertyName>memberDecl.name).expression, SymbolFlags.Value);
13201+
}
13202+
}
13203+
13204+
if (!prop) {
13205+
prop = createSymbol(SymbolFlags.Property | member.flags, member.name);
13206+
}
13207+
1319513208
if (inDestructuringPattern) {
1319613209
// If object literal is an assignment pattern and if the assignment pattern specifies a default value
1319713210
// for the property, make the property optional.
@@ -13259,7 +13272,7 @@ namespace ts {
1325913272
checkNodeDeferred(memberDecl);
1326013273
}
1326113274

13262-
if (hasDynamicName(memberDecl)) {
13275+
if (hasDynamicName(memberDecl) && !(member && member.flags & SymbolFlags.Dynamic)) {
1326313276
if (isNumericName(memberDecl.name)) {
1326413277
hasComputedNumberProperty = true;
1326513278
}

src/compiler/declarationEmitter.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -1297,14 +1297,9 @@ namespace ts {
12971297
function emitDynamicName(entityName: EntityNameExpression) {
12981298
writer.getSymbolAccessibilityDiagnostic = getVariableDeclarationTypeVisibilityError;
12991299
const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration);
1300-
if (visibilityResult.accessibility !== SymbolAccessibility.Accessible) {
1301-
resolver.writeTypeOfExpression(entityName, enclosingDeclaration, TypeFormatFlags.None, writer);
1302-
}
1303-
else {
1304-
handleSymbolAccessibilityError(visibilityResult);
1305-
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName));
1306-
writeTextOfNode(currentText, node.name);
1307-
}
1300+
handleSymbolAccessibilityError(visibilityResult);
1301+
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName));
1302+
writeTextOfNode(currentText, node.name);
13081303
}
13091304

13101305
function emitBindingPattern(bindingPattern: BindingPattern) {

src/compiler/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2610,6 +2610,7 @@ namespace ts {
26102610
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
26112611
reportInaccessibleThisError(): void;
26122612
reportIllegalExtends(): void;
2613+
26132614
}
26142615

26152616
export const enum TypeFormatFlags {
@@ -2880,6 +2881,7 @@ namespace ts {
28802881
exportsSomeValue?: boolean; // True if module exports some value (not just types)
28812882
dynamicMembers?: SymbolTable; // Dynamic members with literal names resolved during check
28822883
resolvedMembers?: SymbolTable;
2884+
dynamicSource?: Symbol;
28832885
}
28842886

28852887
/* @internal */

src/compiler/utilities.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ namespace ts {
6868
clear: () => str = "",
6969
trackSymbol: noop,
7070
reportInaccessibleThisError: noop,
71-
reportIllegalExtends: noop
71+
reportIllegalExtends: noop,
7272
};
7373
}
7474

src/services/utilities.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ namespace ts {
11741174
clear: resetWriter,
11751175
trackSymbol: noop,
11761176
reportInaccessibleThisError: noop,
1177-
reportIllegalExtends: noop
1177+
reportIllegalExtends: noop,
11781178
};
11791179

11801180
function writeIndent() {

tests/baselines/reference/dynamicNames.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//// [module.ts]
44
export const c0 = "a";
55
export const c1 = 1;
6-
const c2 = "a";
76
export interface T0 {
87
[c0]: number;
98
[c1]: string;
@@ -15,7 +14,7 @@ export declare class T1 implements T2 {
1514
export declare class T2 extends T1 {
1615
}
1716
export declare type T3 = {
18-
[c2]: number;
17+
[c0]: number;
1918
[c1]: string;
2019
};
2120

@@ -107,7 +106,6 @@ t0 = t12, t0 = t13, t0 = t14, t0 = t15, t12 = t0, t13 = t0, t14 = t0, t15 = t0;
107106
Object.defineProperty(exports, "__esModule", { value: true });
108107
exports.c0 = "a";
109108
exports.c1 = 1;
110-
const c2 = "a";
111109
//// [main.js]
112110
"use strict";
113111
Object.defineProperty(exports, "__esModule", { value: true });
@@ -158,7 +156,7 @@ export declare class T1 implements T2 {
158156
export declare class T2 extends T1 {
159157
}
160158
export declare type T3 = {
161-
"a": number;
159+
[c0]: number;
162160
[c1]: string;
163161
};
164162
//// [main.d.ts]

tests/baselines/reference/dynamicNames.symbols

+12-15
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ export const c0 = "a";
55
export const c1 = 1;
66
>c1 : Symbol(c1, Decl(module.ts, 1, 12))
77

8-
const c2 = "a";
9-
>c2 : Symbol(c2, Decl(module.ts, 2, 5))
10-
118
export interface T0 {
12-
>T0 : Symbol(T0, Decl(module.ts, 2, 15))
9+
>T0 : Symbol(T0, Decl(module.ts, 1, 20))
1310

1411
[c0]: number;
1512
>c0 : Symbol(c0, Decl(module.ts, 0, 12))
@@ -18,8 +15,8 @@ export interface T0 {
1815
>c1 : Symbol(c1, Decl(module.ts, 1, 12))
1916
}
2017
export declare class T1 implements T2 {
21-
>T1 : Symbol(T1, Decl(module.ts, 6, 1))
22-
>T2 : Symbol(T2, Decl(module.ts, 10, 1))
18+
>T1 : Symbol(T1, Decl(module.ts, 5, 1))
19+
>T2 : Symbol(T2, Decl(module.ts, 9, 1))
2320

2421
[c0]: number;
2522
>c0 : Symbol(c0, Decl(module.ts, 0, 12))
@@ -28,14 +25,14 @@ export declare class T1 implements T2 {
2825
>c1 : Symbol(c1, Decl(module.ts, 1, 12))
2926
}
3027
export declare class T2 extends T1 {
31-
>T2 : Symbol(T2, Decl(module.ts, 10, 1))
32-
>T1 : Symbol(T1, Decl(module.ts, 6, 1))
28+
>T2 : Symbol(T2, Decl(module.ts, 9, 1))
29+
>T1 : Symbol(T1, Decl(module.ts, 5, 1))
3330
}
3431
export declare type T3 = {
35-
>T3 : Symbol(T3, Decl(module.ts, 12, 1))
32+
>T3 : Symbol(T3, Decl(module.ts, 11, 1))
3633

37-
[c2]: number;
38-
>c2 : Symbol(c2, Decl(module.ts, 2, 5))
34+
[c0]: number;
35+
>c0 : Symbol(c0, Decl(module.ts, 0, 12))
3936

4037
[c1]: string;
4138
>c1 : Symbol(c1, Decl(module.ts, 1, 12))
@@ -199,22 +196,22 @@ let t3: T3;
199196
let t0_1: M.T0;
200197
>t0_1 : Symbol(t0_1, Decl(main.ts, 60, 3))
201198
>M : Symbol(M, Decl(main.ts, 1, 6))
202-
>T0 : Symbol(T0, Decl(module.ts, 2, 15))
199+
>T0 : Symbol(T0, Decl(module.ts, 1, 20))
203200

204201
let t1_1: M.T1;
205202
>t1_1 : Symbol(t1_1, Decl(main.ts, 61, 3))
206203
>M : Symbol(M, Decl(main.ts, 1, 6))
207-
>T1 : Symbol(T1, Decl(module.ts, 6, 1))
204+
>T1 : Symbol(T1, Decl(module.ts, 5, 1))
208205

209206
let t2_1: M.T2;
210207
>t2_1 : Symbol(t2_1, Decl(main.ts, 62, 3))
211208
>M : Symbol(M, Decl(main.ts, 1, 6))
212-
>T2 : Symbol(T2, Decl(module.ts, 10, 1))
209+
>T2 : Symbol(T2, Decl(module.ts, 9, 1))
213210

214211
let t3_1: M.T3;
215212
>t3_1 : Symbol(t3_1, Decl(main.ts, 63, 3))
216213
>M : Symbol(M, Decl(main.ts, 1, 6))
217-
>T3 : Symbol(T3, Decl(module.ts, 12, 1))
214+
>T3 : Symbol(T3, Decl(module.ts, 11, 1))
218215

219216
let t4: N.T4;
220217
>t4 : Symbol(t4, Decl(main.ts, 64, 3))

tests/baselines/reference/dynamicNames.types

+20-24
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ export const c1 = 1;
77
>c1 : 1
88
>1 : 1
99

10-
const c2 = "a";
11-
>c2 : "a"
12-
>"a" : "a"
13-
1410
export interface T0 {
1511
>T0 : T0
1612

@@ -37,8 +33,8 @@ export declare class T2 extends T1 {
3733
export declare type T3 = {
3834
>T3 : T3
3935

40-
[c2]: number;
41-
>c2 : "a"
36+
[c0]: number;
37+
>c0 : "a"
4238

4339
[c1]: string;
4440
>c1 : 1
@@ -100,7 +96,7 @@ namespace N {
10096
>T5 : T5
10197
}
10298
export declare type T7 = {
103-
>T7 : { "a": number; "1": string; }
99+
>T7 : { [N.c2]: number; [N.c3]: string; }
104100

105101
[N.c2]: number;
106102
>N.c2 : "a"
@@ -147,7 +143,7 @@ declare class T10 extends T9 {
147143
>T9 : T9
148144
}
149145
declare type T11 = {
150-
>T11 : { "a": number; "1": string; }
146+
>T11 : { [c4]: number; [c5]: string; }
151147

152148
[c4]: number;
153149
>c4 : "a"
@@ -239,9 +235,9 @@ let t6: N.T6;
239235
>T6 : N.T6
240236

241237
let t7: N.T7;
242-
>t7 : { "a": number; "1": string; }
238+
>t7 : { [N.c2]: number; [N.c3]: string; }
243239
>N : any
244-
>T7 : { "a": number; "1": string; }
240+
>T7 : { [N.c2]: number; [N.c3]: string; }
245241

246242
let t8: T8;
247243
>t8 : T8
@@ -256,8 +252,8 @@ let t10: T10;
256252
>T10 : T10
257253

258254
let t11: T11;
259-
>t11 : { "a": number; "1": string; }
260-
>T11 : { "a": number; "1": string; }
255+
>t11 : { [c4]: number; [c5]: string; }
256+
>T11 : { [c4]: number; [c5]: string; }
261257

262258
let t12: T12;
263259
>t12 : T12
@@ -329,49 +325,49 @@ t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7,
329325
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4, t7 = t5, t7 = t6 : N.T6
330326
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4, t7 = t5 : N.T5
331327
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4 : N.T4
332-
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7 : { "a": number; "1": string; }
328+
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7 : { [N.c2]: number; [N.c3]: string; }
333329
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5 : N.T5
334330
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4 : N.T4
335-
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7 : { "a": number; "1": string; }
331+
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7 : { [N.c2]: number; [N.c3]: string; }
336332
>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6 : N.T6
337333
>t4 = t5, t4 = t6, t4 = t7, t5 = t4 : N.T4
338-
>t4 = t5, t4 = t6, t4 = t7 : { "a": number; "1": string; }
334+
>t4 = t5, t4 = t6, t4 = t7 : { [N.c2]: number; [N.c3]: string; }
339335
>t4 = t5, t4 = t6 : N.T6
340336
>t4 = t5 : N.T5
341337
>t4 : N.T4
342338
>t5 : N.T5
343339
>t4 = t6 : N.T6
344340
>t4 : N.T4
345341
>t6 : N.T6
346-
>t4 = t7 : { "a": number; "1": string; }
342+
>t4 = t7 : { [N.c2]: number; [N.c3]: string; }
347343
>t4 : N.T4
348-
>t7 : { "a": number; "1": string; }
344+
>t7 : { [N.c2]: number; [N.c3]: string; }
349345
>t5 = t4 : N.T4
350346
>t5 : N.T5
351347
>t4 : N.T4
352348
>t5 = t6 : N.T6
353349
>t5 : N.T5
354350
>t6 : N.T6
355-
>t5 = t7 : { "a": number; "1": string; }
351+
>t5 = t7 : { [N.c2]: number; [N.c3]: string; }
356352
>t5 : N.T5
357-
>t7 : { "a": number; "1": string; }
353+
>t7 : { [N.c2]: number; [N.c3]: string; }
358354
>t6 = t4 : N.T4
359355
>t6 : N.T6
360356
>t4 : N.T4
361357
>t6 = t5 : N.T5
362358
>t6 : N.T6
363359
>t5 : N.T5
364-
>t6 = t7 : { "a": number; "1": string; }
360+
>t6 = t7 : { [N.c2]: number; [N.c3]: string; }
365361
>t6 : N.T6
366-
>t7 : { "a": number; "1": string; }
362+
>t7 : { [N.c2]: number; [N.c3]: string; }
367363
>t7 = t4 : N.T4
368-
>t7 : { "a": number; "1": string; }
364+
>t7 : { [N.c2]: number; [N.c3]: string; }
369365
>t4 : N.T4
370366
>t7 = t5 : N.T5
371-
>t7 : { "a": number; "1": string; }
367+
>t7 : { [N.c2]: number; [N.c3]: string; }
372368
>t5 : N.T5
373369
>t7 = t6 : N.T6
374-
>t7 : { "a": number; "1": string; }
370+
>t7 : { [N.c2]: number; [N.c3]: string; }
375371
>t6 : N.T6
376372

377373
t0 = t12, t0 = t13, t0 = t14, t0 = t15, t12 = t0, t13 = t0, t14 = t0, t15 = t0;

tests/baselines/reference/dynamicNamesErrors.errors.txt

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
tests/cases/compiler/dynamicNamesErrors.ts(5,5): error TS2300: Duplicate identifier '1'.
22
tests/cases/compiler/dynamicNamesErrors.ts(6,5): error TS2300: Duplicate identifier '1'.
33
tests/cases/compiler/dynamicNamesErrors.ts(19,5): error TS2711: Subsequent property declarations must have the same type. Property '[c1]' must be of type 'number', but here has type 'string'.
4-
tests/cases/compiler/dynamicNamesErrors.ts(25,1): error TS2322: Type 'T2' is not assignable to type 'T1'.
5-
Types of property '"1"' are incompatible.
4+
tests/cases/compiler/dynamicNamesErrors.ts(24,1): error TS2322: Type 'T2' is not assignable to type 'T1'.
5+
Types of property '[c0]' are incompatible.
66
Type 'string' is not assignable to type 'number'.
7-
tests/cases/compiler/dynamicNamesErrors.ts(26,1): error TS2322: Type 'T1' is not assignable to type 'T2'.
8-
Types of property '"1"' are incompatible.
7+
tests/cases/compiler/dynamicNamesErrors.ts(25,1): error TS2322: Type 'T1' is not assignable to type 'T2'.
8+
Types of property '[c0]' are incompatible.
99
Type 'number' is not assignable to type 'string'.
10+
tests/cases/compiler/dynamicNamesErrors.ts(28,6): error TS4033: Property '[c0]' of exported interface has or is using private name 'c0'.
1011

1112

12-
==== tests/cases/compiler/dynamicNamesErrors.ts (5 errors) ====
13+
==== tests/cases/compiler/dynamicNamesErrors.ts (6 errors) ====
1314
const c0 = "1";
1415
const c1 = 1;
1516

@@ -37,16 +38,21 @@ tests/cases/compiler/dynamicNamesErrors.ts(26,1): error TS2322: Type 'T1' is not
3738
!!! error TS2711: Subsequent property declarations must have the same type. Property '[c1]' must be of type 'number', but here has type 'string'.
3839
}
3940

40-
4141
let t1: T1;
4242
let t2: T2;
4343
t1 = t2;
4444
~~
4545
!!! error TS2322: Type 'T2' is not assignable to type 'T1'.
46-
!!! error TS2322: Types of property '"1"' are incompatible.
46+
!!! error TS2322: Types of property '[c0]' are incompatible.
4747
!!! error TS2322: Type 'string' is not assignable to type 'number'.
4848
t2 = t1;
4949
~~
5050
!!! error TS2322: Type 'T1' is not assignable to type 'T2'.
51-
!!! error TS2322: Types of property '"1"' are incompatible.
52-
!!! error TS2322: Type 'number' is not assignable to type 'string'.
51+
!!! error TS2322: Types of property '[c0]' are incompatible.
52+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
53+
54+
export interface T4 {
55+
[c0]: number;
56+
~~
57+
!!! error TS4033: Property '[c0]' of exported interface has or is using private name 'c0'.
58+
}

0 commit comments

Comments
 (0)