@@ -8230,8 +8230,9 @@ namespace ts {
8230
8230
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, includeDeclaredTypes) :
8231
8231
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
8232
8232
type === wildcardType ? wildcardType :
8233
- type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? keyofConstraintType :
8234
- keyofStringsOnly ? getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) :
8233
+ type.flags & TypeFlags.Any ? keyofConstraintType :
8234
+ keyofStringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) :
8235
+ getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.UniqueESSymbol)]) :
8235
8236
getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
8236
8237
getLiteralTypeFromPropertyNames(type, TypeFlags.StringOrNumberLiteralOrUnique);
8237
8238
}
@@ -8303,7 +8304,11 @@ namespace ts {
8303
8304
getIndexInfoOfType(objectType, IndexKind.String) ||
8304
8305
undefined;
8305
8306
if (indexInfo) {
8306
- if (accessExpression && indexInfo.isReadonly && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) {
8307
+ if (accessNode && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
8308
+ const indexNode = accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : accessNode.indexType;
8309
+ error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
8310
+ }
8311
+ else if (accessExpression && indexInfo.isReadonly && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) {
8307
8312
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
8308
8313
}
8309
8314
return indexInfo.type;
@@ -20055,6 +20060,15 @@ namespace ts {
20055
20060
return widened;
20056
20061
}
20057
20062
20063
+ function isTypeParameterWithKeyofConstraint(type: Type) {
20064
+ if (type.flags & TypeFlags.TypeParameter) {
20065
+ const constraintDeclaration = getConstraintDeclaration(<TypeParameter>type);
20066
+ return constraintDeclaration && constraintDeclaration.kind === SyntaxKind.TypeOperator &&
20067
+ (<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword;
20068
+ }
20069
+ return false;
20070
+ }
20071
+
20058
20072
function isLiteralOfContextualType(candidateType: Type, contextualType: Type): boolean {
20059
20073
if (contextualType) {
20060
20074
if (contextualType.flags & TypeFlags.UnionOrIntersection) {
@@ -20066,7 +20080,7 @@ namespace ts {
20066
20080
// this a literal context for literals of that primitive type. For example, given a
20067
20081
// type parameter 'T extends string', infer string literal types for T.
20068
20082
const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType;
20069
- return constraint === keyofConstraintType && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.UniqueESSymbol) ||
20083
+ return isTypeParameterWithKeyofConstraint(contextualType) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.UniqueESSymbol) ||
20070
20084
constraint.flags & TypeFlags.String && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
20071
20085
constraint.flags & TypeFlags.Number && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) ||
20072
20086
constraint.flags & TypeFlags.Boolean && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) ||
0 commit comments