@@ -706,6 +706,13 @@ namespace ts {
706
706
Signature = 1 << 0, // Obtaining contextual signature
707
707
}
708
708
709
+ const enum AccessFlags {
710
+ None = 0,
711
+ NoIndexSignatures = 1 << 0,
712
+ Writing = 1 << 1,
713
+ CacheSymbol = 1 << 2,
714
+ }
715
+
709
716
const enum CallbackCheck {
710
717
None,
711
718
Bivariant,
@@ -9796,16 +9803,16 @@ namespace ts {
9796
9803
return numberIndexInfo !== enumNumberIndexInfo ? numberIndexInfo : undefined;
9797
9804
}
9798
9805
9799
- function getIndexType(type: Type, stringsOnly = keyofStringsOnly): Type {
9800
- return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly))) :
9801
- type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly))) :
9806
+ function getIndexType(type: Type, stringsOnly = keyofStringsOnly, noIndexSignatures?: boolean ): Type {
9807
+ return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures ))) :
9808
+ type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures ))) :
9802
9809
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
9803
9810
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
9804
9811
type === wildcardType ? wildcardType :
9805
9812
type.flags & TypeFlags.Any ? keyofConstraintType :
9806
- stringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) :
9807
- getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) :
9808
- getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
9813
+ stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) :
9814
+ !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) :
9815
+ !noIndexSignatures && getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
9809
9816
getLiteralTypeFromProperties(type, TypeFlags.StringOrNumberLiteralOrUnique);
9810
9817
}
9811
9818
@@ -9877,7 +9884,7 @@ namespace ts {
9877
9884
return false;
9878
9885
}
9879
9886
9880
- function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, writing: boolean, cacheSymbol: boolean ) {
9887
+ function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags ) {
9881
9888
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
9882
9889
const propName = isTypeUsableAsPropertyName(indexType) ?
9883
9890
getPropertyNameFromType(indexType) :
@@ -9896,7 +9903,7 @@ namespace ts {
9896
9903
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop));
9897
9904
return undefined;
9898
9905
}
9899
- if (cacheSymbol ) {
9906
+ if (accessFlags & AccessFlags.CacheSymbol ) {
9900
9907
getNodeLinks(accessNode!).resolvedSymbol = prop;
9901
9908
}
9902
9909
}
@@ -9926,19 +9933,22 @@ namespace ts {
9926
9933
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) ||
9927
9934
getIndexInfoOfType(objectType, IndexKind.String);
9928
9935
if (indexInfo) {
9929
- const isAssignment = accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression));
9930
- if (isAssignment && maybeTypeOfKind(originalObjectType, TypeFlags.Instantiable)) {
9931
- error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType));
9936
+ if (accessFlags & AccessFlags.NoIndexSignatures) {
9937
+ if (accessExpression) {
9938
+ error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType));
9939
+ }
9932
9940
return undefined;
9933
9941
}
9934
9942
if (accessNode && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
9935
9943
const indexNode = getIndexNodeForAccessExpression(accessNode);
9936
9944
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
9945
+ return indexInfo.type;
9937
9946
}
9938
- else if (isAssignment && indexInfo.isReadonly) {
9939
- error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
9940
- }
9941
- else if (writing && indexInfo.isReadonly) {
9947
+ if (indexInfo.isReadonly && (accessFlags & AccessFlags.Writing || accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression)))) {
9948
+ if (accessExpression) {
9949
+ error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
9950
+ return indexInfo.type;
9951
+ }
9942
9952
return undefined;
9943
9953
}
9944
9954
return indexInfo.type;
@@ -10085,10 +10095,10 @@ namespace ts {
10085
10095
}
10086
10096
10087
10097
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression): Type {
10088
- return getIndexedAccessTypeOrUndefined(objectType, indexType, accessNode, /*writing*/ false ) || (accessNode ? errorType : unknownType);
10098
+ return getIndexedAccessTypeOrUndefined(objectType, indexType, accessNode, AccessFlags.None ) || (accessNode ? errorType : unknownType);
10089
10099
}
10090
10100
10091
- function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, writing = false ): Type | undefined {
10101
+ function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, accessFlags = AccessFlags.None ): Type | undefined {
10092
10102
if (objectType === wildcardType || indexType === wildcardType) {
10093
10103
return wildcardType;
10094
10104
}
@@ -10117,7 +10127,7 @@ namespace ts {
10117
10127
const propTypes: Type[] = [];
10118
10128
let wasMissingProp = false;
10119
10129
for (const t of (<UnionType>indexType).types) {
10120
- const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, accessNode, writing, /*cacheSymbol*/ false );
10130
+ const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, accessNode, accessFlags );
10121
10131
if (propType) {
10122
10132
propTypes.push(propType);
10123
10133
}
@@ -10133,9 +10143,9 @@ namespace ts {
10133
10143
if (wasMissingProp) {
10134
10144
return undefined;
10135
10145
}
10136
- return writing ? getIntersectionType(propTypes) : getUnionType(propTypes);
10146
+ return accessFlags & AccessFlags.Writing ? getIntersectionType(propTypes) : getUnionType(propTypes);
10137
10147
}
10138
- return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, accessNode, writing, /*cacheSymbol*/ true );
10148
+ return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol );
10139
10149
}
10140
10150
10141
10151
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
@@ -12831,7 +12841,7 @@ namespace ts {
12831
12841
if (indexType.flags & TypeFlags.StructuredOrInstantiable) {
12832
12842
const keyType = getLowerBoundOfKeyType(indexType, /*isIndexType*/ true);
12833
12843
if (keyType !== indexType && !(keyType.flags & TypeFlags.Never)) {
12834
- const targetType = getIndexedAccessTypeOrUndefined(objectType, keyType, /*accessNode*/ undefined, /*writing*/ true );
12844
+ const targetType = getIndexedAccessTypeOrUndefined(objectType, keyType, /*accessNode*/ undefined, AccessFlags.Writing );
12835
12845
if (targetType && (result = isRelatedTo(source, targetType, reportErrors))) {
12836
12846
return result;
12837
12847
}
@@ -12840,7 +12850,7 @@ namespace ts {
12840
12850
else {
12841
12851
const constraint = getConstraintOfType(objectType);
12842
12852
if (constraint) {
12843
- const targetType = getIndexedAccessTypeOrUndefined(constraint, indexType, /*accessNode*/ undefined, /*writing*/ true );
12853
+ const targetType = getIndexedAccessTypeOrUndefined(constraint, indexType, /*accessNode*/ undefined, AccessFlags.Writing | AccessFlags.NoIndexSignatures );
12844
12854
if (targetType && (result = isRelatedTo(source, targetType, reportErrors))) {
12845
12855
return result;
12846
12856
}
@@ -12859,7 +12869,7 @@ namespace ts {
12859
12869
}
12860
12870
if (!isGenericMappedType(source)) {
12861
12871
const targetConstraint = getConstraintTypeFromMappedType(target);
12862
- const sourceKeys = getIndexType(source);
12872
+ const sourceKeys = getIndexType(source, /*stringsOnly*/ undefined, /*noIndexSignatures*/ true );
12863
12873
const hasOptionalUnionKeys = modifiers & MappedTypeModifiers.IncludeOptional && targetConstraint.flags & TypeFlags.Union;
12864
12874
const filteredByApplicability = hasOptionalUnionKeys ? filterType(targetConstraint, t => !!isRelatedTo(t, sourceKeys)) : undefined;
12865
12875
// A source type T is related to a target type { [P in Q]: X } if Q is related to keyof T and T[Q] is related to X.
@@ -19989,7 +19999,10 @@ namespace ts {
19989
19999
}
19990
20000
19991
20001
const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType;
19992
- const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, node, isAssignmentTarget(node)) || errorType;
20002
+ const accessFlags = isAssignmentTarget(node) ?
20003
+ AccessFlags.Writing | (isGenericObjectType(objectType) ? AccessFlags.NoIndexSignatures : 0) :
20004
+ AccessFlags.None;
20005
+ const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, node, accessFlags) || errorType;
19993
20006
return checkIndexedAccessIndexType(indexedAccessType, node);
19994
20007
}
19995
20008
0 commit comments