mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-03-15 14:05:47 -05:00
Improve unification by moving more logic to getIndexedAccessType
This commit is contained in:
@@ -5738,14 +5738,24 @@ namespace ts {
|
||||
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, indexType));
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
|
||||
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
|
||||
const prop = getPropertyOfType(objectType, escapeIdentifier((<LiteralType>indexType).text));
|
||||
const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ?
|
||||
(<LiteralType>indexType).text :
|
||||
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
|
||||
getPropertyNameForKnownSymbolName((<Identifier>(<PropertyAccessExpression>accessExpression.argumentExpression).name).text) :
|
||||
undefined;
|
||||
if (propName) {
|
||||
const prop = getPropertyOfType(objectType, propName);
|
||||
if (prop) {
|
||||
if (accessExpression && isAssignmentTarget(accessExpression) && isReadonlySymbol(prop)) {
|
||||
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
|
||||
return unknownType;
|
||||
if (accessExpression) {
|
||||
if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) {
|
||||
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
|
||||
return unknownType;
|
||||
}
|
||||
if (cacheSymbol) {
|
||||
getNodeLinks(accessNode).resolvedSymbol = prop;
|
||||
}
|
||||
}
|
||||
return getTypeOfSymbol(prop);
|
||||
}
|
||||
@@ -5798,10 +5808,11 @@ namespace ts {
|
||||
}
|
||||
return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>indexType);
|
||||
}
|
||||
const apparentType = getApparentType(objectType);
|
||||
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) {
|
||||
const propTypes: Type[] = [];
|
||||
for (const t of (<UnionType>indexType).types) {
|
||||
const propType = getPropertyTypeForIndexType(objectType, t, accessNode);
|
||||
const propType = getPropertyTypeForIndexType(apparentType, t, accessNode, /*cacheSymbol*/ false);
|
||||
if (propType === unknownType) {
|
||||
return unknownType;
|
||||
}
|
||||
@@ -5809,7 +5820,7 @@ namespace ts {
|
||||
}
|
||||
return getUnionType(propTypes);
|
||||
}
|
||||
return getPropertyTypeForIndexType(objectType, indexType, accessNode);
|
||||
return getPropertyTypeForIndexType(apparentType, indexType, accessNode, /*cacheSymbol*/ true);
|
||||
}
|
||||
|
||||
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
|
||||
@@ -11644,55 +11655,9 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
const propName = getPropertyNameForIndexedAccess(indexExpression, indexType);
|
||||
if (propName !== undefined) {
|
||||
const prop = getPropertyOfType(getApparentType(objectType), propName);
|
||||
if (prop) {
|
||||
getNodeLinks(node).resolvedSymbol = prop;
|
||||
if (isAssignmentTarget(node)) {
|
||||
if (isReferenceToReadonlyEntity(<Expression>node, prop) || isReferenceThroughNamespaceImport(<Expression>node)) {
|
||||
error(indexExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, propName);
|
||||
return unknownType;
|
||||
}
|
||||
}
|
||||
return getTypeOfSymbol(prop);
|
||||
}
|
||||
}
|
||||
|
||||
return getIndexedAccessType(objectType, indexType, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* If indexArgumentExpression is a string literal or number literal, returns its text.
|
||||
* If indexArgumentExpression is a constant value, returns its string value.
|
||||
* If indexArgumentExpression is a well known symbol, returns the property name corresponding
|
||||
* to this symbol, as long as it is a proper symbol reference.
|
||||
* Otherwise, returns undefined.
|
||||
*/
|
||||
function getPropertyNameForIndexedAccess(indexExpression: Expression, indexType: Type): string {
|
||||
if (indexExpression.kind === SyntaxKind.StringLiteral || indexExpression.kind === SyntaxKind.NumericLiteral) {
|
||||
return (<LiteralExpression>indexExpression).text;
|
||||
}
|
||||
if (indexExpression.kind === SyntaxKind.ElementAccessExpression || indexExpression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
const value = getConstantValue(<ElementAccessExpression | PropertyAccessExpression>indexExpression);
|
||||
if (value !== undefined) {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
if (checkThatExpressionIsProperSymbolReference(indexExpression, indexType, /*reportError*/ false)) {
|
||||
const rightHandSideName = (<Identifier>(<PropertyAccessExpression>indexExpression).name).text;
|
||||
return getPropertyNameForKnownSymbolName(rightHandSideName);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A proper symbol reference requires the following:
|
||||
* 1. The property access denotes a property that exists
|
||||
* 2. The expression is of the form Symbol.<identifier>
|
||||
* 3. The property access is of the primitive type symbol.
|
||||
* 4. Symbol in this context resolves to the global Symbol object
|
||||
*/
|
||||
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
|
||||
if (expressionType === unknownType) {
|
||||
// There is already an error, so no need to report one.
|
||||
|
||||
Reference in New Issue
Block a user