From b49a34375dd88fef1d66062a720e43fef15f415b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 8 Apr 2019 06:36:00 -1000 Subject: [PATCH] Simplify obtaining base constraint of T[K] for writing --- src/compiler/checker.ts | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 71c05634eaf..94e9fd30a79 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7236,7 +7236,7 @@ namespace ts { // because of constraints on type parameters (e.g. 'keyof T' for a constrained T). // The isIndexType flag indicates that the type is the index type of an indexed // access that is the target of an assignment. - function getLowerBoundOfKeyType(type: Type, isIndexType: boolean): Type { + function getLowerBoundOfKeyType(type: Type): Type { if (type.flags & (TypeFlags.Any | TypeFlags.Primitive)) { return type; } @@ -7246,7 +7246,7 @@ namespace ts { if (type.flags & TypeFlags.Conditional) { if ((type).root.isDistributive) { const checkType = (type).checkType; - const constraint = getLowerBoundOfKeyType(checkType, isIndexType); + const constraint = getLowerBoundOfKeyType(checkType); if (constraint !== checkType) { const mapper = makeUnaryTypeMapper((type).root.checkType, constraint); return getConditionalTypeInstantiation(type, combineTypeMappers(mapper, (type).mapper)); @@ -7255,13 +7255,10 @@ namespace ts { return type; } if (type.flags & TypeFlags.Union) { - return getUnionType(sameMap((type).types, t => getLowerBoundOfKeyType(t, isIndexType))); + return getUnionType(sameMap((type).types, getLowerBoundOfKeyType)); } if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(sameMap((type).types, t => getLowerBoundOfKeyType(t, isIndexType))); - } - if (isIndexType && type.flags & TypeFlags.Instantiable) { - return getLowerBoundOfKeyType(getConstraintOfType(type) || neverType, isIndexType); + return getIntersectionType(sameMap((type).types, getLowerBoundOfKeyType)); } return neverType; } @@ -7294,7 +7291,7 @@ namespace ts { } } else { - forEachType(getLowerBoundOfKeyType(constraintType, /*isIndexType*/ false), addMemberForKeyType); + forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); } setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); @@ -12879,27 +12876,18 @@ namespace ts { } } else if (target.flags & TypeFlags.IndexedAccess) { - // A type S is related to a type T[K], where T and K aren't both type variables, if S is related to C, - // where C is the base constraint of T[K] + // A type S is related to a type T[K] if S is related to C, where C is the base + // constraint of T[K] for writing. if (relation !== identityRelation) { const objectType = (target).objectType; const indexType = (target).indexType; - if (indexType.flags & TypeFlags.StructuredOrInstantiable) { - const keyType = getLowerBoundOfKeyType(indexType, /*isIndexType*/ true); - if (keyType !== indexType && !(keyType.flags & TypeFlags.Never)) { - const targetType = getIndexedAccessTypeOrUndefined(objectType, keyType, /*accessNode*/ undefined, AccessFlags.Writing); - if (targetType && (result = isRelatedTo(source, targetType, reportErrors))) { - return result; - } - } - } - else { - const constraint = getConstraintOfType(objectType); - if (constraint) { - const targetType = getIndexedAccessTypeOrUndefined(constraint, indexType, /*accessNode*/ undefined, AccessFlags.Writing | AccessFlags.NoIndexSignatures); - if (targetType && (result = isRelatedTo(source, targetType, reportErrors))) { - return result; - } + const baseObjectType = getBaseConstraintOfType(objectType) || objectType; + const baseIndexType = getBaseConstraintOfType(indexType) || indexType; + if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { + const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); + const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, /*accessNode*/ undefined, accessFlags); + if (constraint && (result = isRelatedTo(source, constraint, reportErrors))) { + return result; } } }