From 9e4e215a030d5931dbfcb666352d6226ab742bf7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 18 Apr 2018 15:43:22 -0700 Subject: [PATCH] Revise IndexType to have stringsOnly property --- src/compiler/checker.ts | 33 +++++++++++++++++---------------- src/compiler/types.ts | 8 ++++---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 67867074fdb..62b4f537ec6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8191,16 +8191,17 @@ namespace ts { return links.resolvedType; } - function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, includeDeclaredTypes?: boolean) { - const cacheLocation = includeDeclaredTypes ? "resolvedDeclaredIndexType" : "resolvedIndexType"; - if (!type[cacheLocation]) { - type[cacheLocation] = createType(TypeFlags.Index); - type[cacheLocation].type = type; - if (includeDeclaredTypes) { - type[cacheLocation].isDeclaredType = true; - } - } - return type[cacheLocation]; + function createIndexType(type: InstantiableType | UnionOrIntersectionType, stringsOnly: boolean) { + const result = createType(TypeFlags.Index); + result.type = type; + result.stringsOnly = stringsOnly; + return result; + } + + function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, stringsOnly: boolean) { + return stringsOnly ? + type.resolvedStringIndexType || (type.resolvedStringIndexType = createIndexType(type, /*stringsOnly*/ true)) : + type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false)); } function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) { @@ -8225,13 +8226,13 @@ namespace ts { return numberIndexInfo !== enumNumberIndexInfo ? numberIndexInfo : undefined; } - function getIndexType(type: Type, includeDeclaredTypes?: boolean): Type { - return type.flags & TypeFlags.Intersection ? getUnionType(map((type).types, t => getIndexType(t, includeDeclaredTypes))) : - maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type, includeDeclaredTypes) : + function getIndexType(type: Type, stringsOnly = keyofStringsOnly): Type { + return type.flags & TypeFlags.Intersection ? getUnionType(map((type).types, t => getIndexType(t, stringsOnly))) : + maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type, stringsOnly) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(type) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Any ? keyofConstraintType : - keyofStringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) : + stringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) : getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.UniqueESSymbol)]) : getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) : getLiteralTypeFromPropertyNames(type, TypeFlags.StringOrNumberLiteralOrUnique); @@ -10438,7 +10439,7 @@ namespace ts { // constraint of T. const constraint = getConstraintForRelation((target).type); if (constraint) { - if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).isDeclaredType), reportErrors)) { + if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) { return result; } } @@ -21010,7 +21011,7 @@ namespace ts { // Check if the index type is assignable to 'keyof T' for the object type. const objectType = (type).objectType; const indexType = (type).indexType; - if (isTypeAssignableTo(indexType, getIndexType(objectType, /*includeDeclaredTypes*/ true))) { + if (isTypeAssignableTo(indexType, getIndexType(objectType, /*stringsOnly*/ false))) { if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType) & MappedTypeModifiers.IncludeReadonly) { error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 894c8d3c8e2..4db1c342098 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3761,7 +3761,7 @@ namespace ts { /* @internal */ resolvedIndexType: IndexType; /* @internal */ - resolvedDeclaredIndexType: IndexType; + resolvedStringIndexType: IndexType; /* @internal */ resolvedBaseConstraint: Type; /* @internal */ @@ -3850,7 +3850,7 @@ namespace ts { /* @internal */ resolvedIndexType?: IndexType; /* @internal */ - resolvedDeclaredIndexType?: IndexType; + resolvedStringIndexType?: IndexType; } // Type parameters (TypeFlags.TypeParameter) @@ -3882,9 +3882,9 @@ namespace ts { // keyof T types (TypeFlags.Index) export interface IndexType extends InstantiableType { - /* @internal */ - isDeclaredType?: boolean; type: InstantiableType | UnionOrIntersectionType; + /* @internal */ + stringsOnly: boolean; } export interface ConditionalRoot {