@@ -2342,6 +2342,26 @@ namespace ts {
2342
2342
return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node);
2343
2343
}
2344
2344
2345
+ function getTextOfPropertyName(name: PropertyName): string {
2346
+ switch (name.kind) {
2347
+ case SyntaxKind.Identifier:
2348
+ return (<Identifier>name).text;
2349
+ case SyntaxKind.StringLiteral:
2350
+ case SyntaxKind.NumericLiteral:
2351
+ return (<LiteralExpression>name).text;
2352
+ case SyntaxKind.ComputedPropertyName:
2353
+ if (isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind)) {
2354
+ return (<LiteralExpression>(<ComputedPropertyName>name).expression).text;
2355
+ }
2356
+ }
2357
+
2358
+ return undefined;
2359
+ }
2360
+
2361
+ function isComputedNonLiteralName(name: PropertyName): boolean {
2362
+ return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind);
2363
+ }
2364
+
2345
2365
// Return the inferred type for a binding element
2346
2366
function getTypeForBindingElement(declaration: BindingElement): Type {
2347
2367
const pattern = <BindingPattern>declaration.parent;
@@ -2364,10 +2384,17 @@ namespace ts {
2364
2384
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
2365
2385
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
2366
2386
const name = declaration.propertyName || <Identifier>declaration.name;
2387
+ if (isComputedNonLiteralName(name)) {
2388
+ // computed properties with non-literal names are treated as 'any'
2389
+ return anyType;
2390
+ }
2391
+
2367
2392
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
2368
2393
// or otherwise the type of the string index signature.
2369
- type = getTypeOfPropertyOfType(parentType, name.text) ||
2370
- isNumericLiteralName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
2394
+ const text = getTextOfPropertyName(name);
2395
+
2396
+ type = getTypeOfPropertyOfType(parentType, text) ||
2397
+ isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
2371
2398
getIndexTypeOfType(parentType, IndexKind.String);
2372
2399
if (!type) {
2373
2400
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
@@ -2478,10 +2505,18 @@ namespace ts {
2478
2505
// Return the type implied by an object binding pattern
2479
2506
function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
2480
2507
const members: SymbolTable = {};
2508
+ let hasComputedProperties = false;
2481
2509
forEach(pattern.elements, e => {
2482
- const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
2483
2510
const name = e.propertyName || <Identifier>e.name;
2484
- const symbol = <TransientSymbol>createSymbol(flags, name.text);
2511
+ if (isComputedNonLiteralName(name)) {
2512
+ // do not include computed properties in the implied type
2513
+ hasComputedProperties = true;
2514
+ return;
2515
+ }
2516
+
2517
+ const text = getTextOfPropertyName(name);
2518
+ const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
2519
+ const symbol = <TransientSymbol>createSymbol(flags, text);
2485
2520
symbol.type = getTypeFromBindingElement(e, includePatternInType);
2486
2521
symbol.bindingElement = e;
2487
2522
members[symbol.name] = symbol;
@@ -2490,6 +2525,9 @@ namespace ts {
2490
2525
if (includePatternInType) {
2491
2526
result.pattern = pattern;
2492
2527
}
2528
+ if (hasComputedProperties) {
2529
+ result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties;
2530
+ }
2493
2531
return result;
2494
2532
}
2495
2533
@@ -5013,7 +5051,7 @@ namespace ts {
5013
5051
}
5014
5052
5015
5053
function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
5016
- if (someConstituentTypeHasKind(target, TypeFlags.ObjectType)) {
5054
+ if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && someConstituentTypeHasKind(target, TypeFlags.ObjectType)) {
5017
5055
for (const prop of getPropertiesOfObjectType(source)) {
5018
5056
if (!isKnownProperty(target, prop.name)) {
5019
5057
if (reportErrors) {
@@ -7467,6 +7505,7 @@ namespace ts {
7467
7505
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
7468
7506
let typeFlags: TypeFlags = 0;
7469
7507
7508
+ let patternWithComputedProperties = false;
7470
7509
for (const memberDecl of node.properties) {
7471
7510
let member = memberDecl.symbol;
7472
7511
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
@@ -7494,8 +7533,11 @@ namespace ts {
7494
7533
if (isOptional) {
7495
7534
prop.flags |= SymbolFlags.Optional;
7496
7535
}
7536
+ if (hasDynamicName(memberDecl)) {
7537
+ patternWithComputedProperties = true;
7538
+ }
7497
7539
}
7498
- else if (contextualTypeHasPattern) {
7540
+ else if (contextualTypeHasPattern && !(contextualType.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) ) {
7499
7541
// If object literal is contextually typed by the implied type of a binding pattern, and if the
7500
7542
// binding pattern specifies a default value for the property, make the property optional.
7501
7543
const impliedProp = getPropertyOfType(contextualType, member.name);
@@ -7552,7 +7594,7 @@ namespace ts {
7552
7594
const numberIndexType = getIndexType(IndexKind.Number);
7553
7595
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType);
7554
7596
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral;
7555
- result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
7597
+ result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0) ;
7556
7598
if (inDestructuringPattern) {
7557
7599
result.pattern = node;
7558
7600
}
@@ -10082,19 +10124,27 @@ namespace ts {
10082
10124
const properties = node.properties;
10083
10125
for (const p of properties) {
10084
10126
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
10085
- // TODO(andersh): Computed property support
10086
- const name = <Identifier>(<PropertyAssignment>p).name;
10127
+ const name = <PropertyName>(<PropertyAssignment>p).name;
10128
+ if (name.kind === SyntaxKind.ComputedPropertyName) {
10129
+ checkComputedPropertyName(<ComputedPropertyName>name);
10130
+ }
10131
+ if (isComputedNonLiteralName(name)) {
10132
+ continue;
10133
+ }
10134
+
10135
+ const text = getTextOfPropertyName(name);
10087
10136
const type = isTypeAny(sourceType)
10088
10137
? sourceType
10089
- : getTypeOfPropertyOfType(sourceType, name. text) ||
10090
- isNumericLiteralName(name. text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
10138
+ : getTypeOfPropertyOfType(sourceType, text) ||
10139
+ isNumericLiteralName(text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
10091
10140
getIndexTypeOfType(sourceType, IndexKind.String);
10092
10141
if (type) {
10093
10142
if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
10094
10143
checkDestructuringAssignment(<ShorthandPropertyAssignment>p, type);
10095
10144
}
10096
10145
else {
10097
- checkDestructuringAssignment((<PropertyAssignment>p).initializer || name, type);
10146
+ // non-shorthand property assignments should always have initializers
10147
+ checkDestructuringAssignment((<PropertyAssignment>p).initializer, type);
10098
10148
}
10099
10149
}
10100
10150
else {
@@ -12227,6 +12277,14 @@ namespace ts {
12227
12277
checkExpressionCached(node.initializer);
12228
12278
}
12229
12279
}
12280
+
12281
+ if (node.kind === SyntaxKind.BindingElement) {
12282
+ // check computed properties inside property names of binding elements
12283
+ if (node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName) {
12284
+ checkComputedPropertyName(<ComputedPropertyName>node.propertyName);
12285
+ }
12286
+ }
12287
+
12230
12288
// For a binding pattern, check contained binding elements
12231
12289
if (isBindingPattern(node.name)) {
12232
12290
forEach((<BindingPattern>node.name).elements, checkSourceElement);
@@ -13338,11 +13396,14 @@ namespace ts {
13338
13396
const enumIsConst = isConst(node);
13339
13397
13340
13398
for (const member of node.members) {
13341
- if (member.name.kind === SyntaxKind.ComputedPropertyName ) {
13399
+ if (isComputedNonLiteralName(<PropertyName> member.name) ) {
13342
13400
error(member.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums);
13343
13401
}
13344
- else if (isNumericLiteralName((<Identifier>member.name).text)) {
13345
- error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name);
13402
+ else {
13403
+ const text = getTextOfPropertyName(<PropertyName>member.name);
13404
+ if (isNumericLiteralName(text)) {
13405
+ error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name);
13406
+ }
13346
13407
}
13347
13408
13348
13409
const previousEnumMemberIsNonConstant = autoValue === undefined;
@@ -15800,7 +15861,7 @@ namespace ts {
15800
15861
}
15801
15862
15802
15863
function checkGrammarForNonSymbolComputedProperty(node: DeclarationName, message: DiagnosticMessage) {
15803
- if (node.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically((<ComputedPropertyName> node).expression )) {
15864
+ if (isDynamicName( node)) {
15804
15865
return grammarErrorOnNode(node, message);
15805
15866
}
15806
15867
}
0 commit comments