@@ -5738,14 +5738,24 @@ namespace ts {
57385738 return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, indexType));
57395739 }
57405740
5741- function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode? : ElementAccessExpression | IndexedAccessTypeNode) {
5741+ function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean ) {
57425742 const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
5743- if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
5744- const prop = getPropertyOfType(objectType, escapeIdentifier((<LiteralType>indexType).text));
5743+ const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ?
5744+ (<LiteralType>indexType).text :
5745+ accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
5746+ getPropertyNameForKnownSymbolName((<Identifier>(<PropertyAccessExpression>accessExpression.argumentExpression).name).text) :
5747+ undefined;
5748+ if (propName) {
5749+ const prop = getPropertyOfType(objectType, propName);
57455750 if (prop) {
5746- if (accessExpression && isAssignmentTarget(accessExpression) && isReadonlySymbol(prop)) {
5747- error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
5748- return unknownType;
5751+ if (accessExpression) {
5752+ if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) {
5753+ error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
5754+ return unknownType;
5755+ }
5756+ if (cacheSymbol) {
5757+ getNodeLinks(accessNode).resolvedSymbol = prop;
5758+ }
57495759 }
57505760 return getTypeOfSymbol(prop);
57515761 }
@@ -5798,18 +5808,19 @@ namespace ts {
57985808 }
57995809 return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>indexType);
58005810 }
5811+ const apparentType = getApparentType(objectType);
58015812 if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) {
58025813 const propTypes: Type[] = [];
58035814 for (const t of (<UnionType>indexType).types) {
5804- const propType = getPropertyTypeForIndexType(objectType , t, accessNode);
5815+ const propType = getPropertyTypeForIndexType(apparentType , t, accessNode, /*cacheSymbol*/ false );
58055816 if (propType === unknownType) {
58065817 return unknownType;
58075818 }
58085819 propTypes.push(propType);
58095820 }
58105821 return getUnionType(propTypes);
58115822 }
5812- return getPropertyTypeForIndexType(objectType , indexType, accessNode);
5823+ return getPropertyTypeForIndexType(apparentType , indexType, accessNode, /*cacheSymbol*/ true );
58135824 }
58145825
58155826 function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
@@ -11644,55 +11655,9 @@ namespace ts {
1164411655 return unknownType;
1164511656 }
1164611657
11647- const propName = getPropertyNameForIndexedAccess(indexExpression, indexType);
11648- if (propName !== undefined) {
11649- const prop = getPropertyOfType(getApparentType(objectType), propName);
11650- if (prop) {
11651- getNodeLinks(node).resolvedSymbol = prop;
11652- if (isAssignmentTarget(node)) {
11653- if (isReferenceToReadonlyEntity(<Expression>node, prop) || isReferenceThroughNamespaceImport(<Expression>node)) {
11654- error(indexExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, propName);
11655- return unknownType;
11656- }
11657- }
11658- return getTypeOfSymbol(prop);
11659- }
11660- }
11661-
1166211658 return getIndexedAccessType(objectType, indexType, node);
1166311659 }
1166411660
11665- /**
11666- * If indexArgumentExpression is a string literal or number literal, returns its text.
11667- * If indexArgumentExpression is a constant value, returns its string value.
11668- * If indexArgumentExpression is a well known symbol, returns the property name corresponding
11669- * to this symbol, as long as it is a proper symbol reference.
11670- * Otherwise, returns undefined.
11671- */
11672- function getPropertyNameForIndexedAccess(indexExpression: Expression, indexType: Type): string {
11673- if (indexExpression.kind === SyntaxKind.StringLiteral || indexExpression.kind === SyntaxKind.NumericLiteral) {
11674- return (<LiteralExpression>indexExpression).text;
11675- }
11676- if (indexExpression.kind === SyntaxKind.ElementAccessExpression || indexExpression.kind === SyntaxKind.PropertyAccessExpression) {
11677- const value = getConstantValue(<ElementAccessExpression | PropertyAccessExpression>indexExpression);
11678- if (value !== undefined) {
11679- return value.toString();
11680- }
11681- }
11682- if (checkThatExpressionIsProperSymbolReference(indexExpression, indexType, /*reportError*/ false)) {
11683- const rightHandSideName = (<Identifier>(<PropertyAccessExpression>indexExpression).name).text;
11684- return getPropertyNameForKnownSymbolName(rightHandSideName);
11685- }
11686- return undefined;
11687- }
11688-
11689- /**
11690- * A proper symbol reference requires the following:
11691- * 1. The property access denotes a property that exists
11692- * 2. The expression is of the form Symbol.<identifier>
11693- * 3. The property access is of the primitive type symbol.
11694- * 4. Symbol in this context resolves to the global Symbol object
11695- */
1169611661 function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
1169711662 if (expressionType === unknownType) {
1169811663 // There is already an error, so no need to report one.
0 commit comments