@@ -7890,7 +7890,7 @@ namespace ts {
78907890 }
78917891
78927892 function getSimplifiedTypeOrConstraint(type: Type) {
7893- const simplified = getSimplifiedType(type, /*writing*/ false );
7893+ const simplified = getSimplifiedType(type);
78947894 return simplified !== type ? simplified : getConstraintOfType(type);
78957895 }
78967896
@@ -7935,7 +7935,7 @@ namespace ts {
79357935 // a union - once negated types exist and are applied to the conditional false branch, this "constraint"
79367936 // likely doesn't need to exist.
79377937 if (type.root.isDistributive && type.restrictiveInstantiation !== type) {
7938- const simplified = getSimplifiedType(type.checkType, /*writing*/ false );
7938+ const simplified = getSimplifiedType(type.checkType);
79397939 const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified;
79407940 if (constraint && constraint !== type.checkType) {
79417941 const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
@@ -8037,7 +8037,7 @@ namespace ts {
80378037 return t.immediateBaseConstraint = noConstraintType;
80388038 }
80398039 constraintDepth++;
8040- let result = computeBaseConstraint(getSimplifiedType(t, /*writing*/ false ));
8040+ let result = computeBaseConstraint(getSimplifiedType(t));
80418041 constraintDepth--;
80428042 if (!popTypeResolution()) {
80438043 if (t.flags & TypeFlags.TypeParameter) {
@@ -10253,9 +10253,23 @@ namespace ts {
1025310253 const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
1025410254 type.objectType = objectType;
1025510255 type.indexType = indexType;
10256+ type.writing = false;
1025610257 return type;
1025710258 }
1025810259
10260+ function getWritingIndexedAccessType(type: IndexedAccessType) {
10261+ const id = "w," + type.objectType.id + "," + type.indexType.id;
10262+ let writeType = indexedAccessTypes.get(id);
10263+ if (!writeType) {
10264+ writeType = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
10265+ writeType.objectType = type.objectType;
10266+ writeType.indexType = type.indexType;
10267+ writeType.writing = true;
10268+ indexedAccessTypes.set(id, writeType);
10269+ }
10270+ return writeType;
10271+ }
10272+
1025910273 /**
1026010274 * Returns if a type is or consists of a JSLiteral object type
1026110275 * In addition to objects which are directly literals,
@@ -10462,9 +10476,9 @@ namespace ts {
1046210476 return !!(type.flags & TypeFlags.TypeParameter && (<TypeParameter>type).isThisType);
1046310477 }
1046410478
10465- function getSimplifiedType(type: Type, writing: boolean ): Type {
10466- return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type, writing ) :
10467- type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(<ConditionalType>type, writing ) :
10479+ function getSimplifiedType(type: Type): Type {
10480+ return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type) :
10481+ type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(<ConditionalType>type) :
1046810482 type;
1046910483 }
1047010484
@@ -10473,7 +10487,7 @@ namespace ts {
1047310487 // (T | U)[K] -> T[K] & U[K] (writing)
1047410488 // (T & U)[K] -> T[K] & U[K]
1047510489 if (objectType.flags & TypeFlags.UnionOrIntersection) {
10476- const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing ));
10490+ const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType)));
1047710491 return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types);
1047810492 }
1047910493 }
@@ -10482,24 +10496,25 @@ namespace ts {
1048210496 // T[A | B] -> T[A] | T[B] (reading)
1048310497 // T[A | B] -> T[A] & T[B] (writing)
1048410498 if (indexType.flags & TypeFlags.Union) {
10485- const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing ));
10499+ const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t)));
1048610500 return writing ? getIntersectionType(types) : getUnionType(types);
1048710501 }
1048810502 }
1048910503
1049010504 // Transform an indexed access to a simpler form, if possible. Return the simpler form, or return
1049110505 // the type itself if no transformation is possible. The writing flag indicates that the type is
1049210506 // the target of an assignment.
10493- function getSimplifiedIndexedAccessType(type: IndexedAccessType, writing: boolean): Type {
10507+ function getSimplifiedIndexedAccessType(type: IndexedAccessType): Type {
10508+ const writing = type.writing;
1049410509 const cache = writing ? "simplifiedForWriting" : "simplifiedForReading";
1049510510 if (type[cache]) {
1049610511 return type[cache] === circularConstraintType ? type : type[cache]!;
1049710512 }
1049810513 type[cache] = circularConstraintType;
1049910514 // We recursively simplify the object type as it may in turn be an indexed access type. For example, with
1050010515 // '{ [P in T]: { [Q in U]: number } }[T][U]' we want to first simplify the inner indexed access type.
10501- const objectType = getSimplifiedType(type.objectType, writing );
10502- const indexType = getSimplifiedType(type.indexType, writing );
10516+ const objectType = getSimplifiedType(type.objectType);
10517+ const indexType = getSimplifiedType(type.indexType);
1050310518 // T[A | B] -> T[A] | T[B] (reading)
1050410519 // T[A | B] -> T[A] & T[B] (writing)
1050510520 const distributedOverIndex = distributeObjectOverIndexType(objectType, indexType, writing);
@@ -10523,20 +10538,20 @@ namespace ts {
1052310538 // that substitutes the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we
1052410539 // construct the type Box<T[X]>.
1052510540 if (isGenericMappedType(objectType)) {
10526- return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing ));
10541+ return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t));
1052710542 }
1052810543 return type[cache] = type;
1052910544 }
1053010545
10531- function getSimplifiedConditionalType(type: ConditionalType, writing: boolean ) {
10546+ function getSimplifiedConditionalType(type: ConditionalType) {
1053210547 const checkType = type.checkType;
1053310548 const extendsType = type.extendsType;
1053410549 const trueType = getTrueTypeFromConditionalType(type);
1053510550 const falseType = getFalseTypeFromConditionalType(type);
1053610551 // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`.
1053710552 if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) {
1053810553 if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true
10539- return getSimplifiedType(trueType, writing );
10554+ return getSimplifiedType(trueType);
1054010555 }
1054110556 else if (isIntersectionEmpty(checkType, extendsType)) { // Always false
1054210557 return neverType;
@@ -10547,7 +10562,7 @@ namespace ts {
1054710562 return neverType;
1054810563 }
1054910564 else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false
10550- return getSimplifiedType(falseType, writing );
10565+ return getSimplifiedType(falseType);
1055110566 }
1055210567 }
1055310568 return type;
@@ -10589,7 +10604,7 @@ namespace ts {
1058910604 return objectType;
1059010605 }
1059110606 // Defer the operation by creating an indexed access type.
10592- const id = objectType.id + "," + indexType.id;
10607+ const id = "r," + objectType.id + "," + indexType.id;
1059310608 let type = indexedAccessTypes.get(id);
1059410609 if (!type) {
1059510610 indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType));
@@ -12812,10 +12827,10 @@ namespace ts {
1281212827 target = (<SubstitutionType>target).typeVariable;
1281312828 }
1281412829 if (source.flags & TypeFlags.Simplifiable) {
12815- source = getSimplifiedType(source, /*writing*/ false );
12830+ source = getSimplifiedType(source);
1281612831 }
1281712832 if (target.flags & TypeFlags.Simplifiable) {
12818- target = getSimplifiedType(target, /*writing*/ true );
12833+ target = getSimplifiedType(target);
1281912834 }
1282012835
1282112836 // Try to see if we're relating something like `Foo` -> `Bar | null | undefined`.
@@ -15653,16 +15668,16 @@ namespace ts {
1565315668 }
1565415669 else {
1565515670 // Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine
15656- const simplified = getSimplifiedType(target, /*writing*/ false );
15671+ const simplified = getSimplifiedType(target);
1565715672 if (simplified !== target) {
1565815673 invokeOnce(source, simplified, inferFromTypes);
1565915674 }
1566015675 else if (target.flags & TypeFlags.IndexedAccess) {
15661- const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false );
15676+ const indexType = getSimplifiedType((target as IndexedAccessType).indexType);
1566215677 // Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider
1566315678 // that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can.
1566415679 if (indexType.flags & TypeFlags.Instantiable) {
15665- const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false ), indexType, /*writing*/ false );
15680+ const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType), indexType, (target as IndexedAccessType).writing );
1566615681 if (simplified && simplified !== target) {
1566715682 invokeOnce(source, simplified, inferFromTypes);
1566815683 }
@@ -24738,6 +24753,7 @@ namespace ts {
2473824753 if (checkReferenceExpression(left, Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access)
2473924754 && (!isIdentifier(left) || unescapeLeadingUnderscores(left.escapedText) !== "exports")) {
2474024755 // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported
24756+ leftType = leftType.flags & TypeFlags.IndexedAccess ? getWritingIndexedAccessType(<IndexedAccessType>leftType) : leftType;
2474124757 checkTypeAssignableToAndOptionallyElaborate(valueType, leftType, left, right);
2474224758 }
2474324759 }
0 commit comments