@@ -19072,6 +19072,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1907219072 return reportedError;
1907319073 }
1907419074
19075+ /**
19076+ * Assumes `target` type is assignable to the `Iterable` type, if `Iterable` is defined,
19077+ * or that it's an array or tuple-like type, if `Iterable` is not defined.
19078+ */
19079+ function elaborateIterableOrArrayLikeTargetElementwise(
19080+ iterator: ElaborationIterator,
19081+ source: Type,
19082+ target: Type,
19083+ relation: Map<string, RelationComparisonResult>,
19084+ containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
19085+ errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
19086+ ) {
19087+ const tupleOrArrayLikeTargetParts = filterType(target, isArrayOrTupleLikeType);
19088+ const nonTupleOrArrayLikeTargetParts = filterType(target, t => !isArrayOrTupleLikeType(t));
19089+ // If `nonTupleOrArrayLikeTargetParts` is not `never`, then that should mean `Iterable` is defined.
19090+ const iterationType = nonTupleOrArrayLikeTargetParts !== neverType
19091+ ? getIterationTypeOfIterable(IterationUse.ForOf, IterationTypeKind.Yield, nonTupleOrArrayLikeTargetParts, /*errorNode*/ undefined)
19092+ : undefined;
19093+
19094+ let reportedError = false;
19095+ for (let status = iterator.next(); !status.done; status = iterator.next()) {
19096+ const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value;
19097+ let targetPropType = iterationType;
19098+ const targetIndexedPropType = tupleOrArrayLikeTargetParts !== neverType ? getBestMatchIndexedAccessTypeOrUndefined(source, tupleOrArrayLikeTargetParts, nameType) : undefined;
19099+ if (targetIndexedPropType && !(targetIndexedPropType.flags & TypeFlags.IndexedAccess)) { // Don't elaborate on indexes on generic variables
19100+ targetPropType = iterationType ? getUnionType([iterationType, targetIndexedPropType]) : targetIndexedPropType;
19101+ }
19102+ if (!targetPropType) continue;
19103+ let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType);
19104+ if (!sourcePropType) continue;
19105+ const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined);
19106+ if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) {
19107+ const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer);
19108+ reportedError = true;
19109+ if (!elaborated) {
19110+ // Issue error on the prop itself, since the prop couldn't elaborate the error
19111+ const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {};
19112+ // Use the expression type, if available
19113+ const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType;
19114+ if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) {
19115+ const diag = createDiagnosticForNode(prop, Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, typeToString(specificSource), typeToString(targetPropType));
19116+ diagnostics.add(diag);
19117+ resultObj.errors = [diag];
19118+ }
19119+ else {
19120+ const targetIsOptional = !!(propName && (getPropertyOfType(tupleOrArrayLikeTargetParts, propName) || unknownSymbol).flags & SymbolFlags.Optional);
19121+ const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional);
19122+ targetPropType = removeMissingType(targetPropType, targetIsOptional);
19123+ sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional);
19124+ const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj);
19125+ if (result && specificSource !== sourcePropType) {
19126+ // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType
19127+ checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj);
19128+ }
19129+ }
19130+ }
19131+ }
19132+ }
19133+ return reportedError;
19134+ }
19135+
19136+
1907519137 function *generateJsxAttributes(node: JsxAttributes): ElaborationIterator {
1907619138 if (!length(node.properties)) return;
1907719139 for (const prop of node.properties) {
@@ -19138,13 +19200,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1913819200 return result;
1913919201 }
1914019202 const moreThanOneRealChildren = length(validChildren) > 1;
19141- const arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType);
19142- const nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t));
19203+ let arrayLikeTargetParts: Type;
19204+ let nonArrayLikeTargetParts: Type;
19205+ const iterableType = getGlobalIterableType(/*reportErrors*/ false);
19206+ if (iterableType !== emptyGenericType) {
19207+ const anyIterable = createIterableType(anyType);
19208+ arrayLikeTargetParts = filterType(childrenTargetType, t => isTypeAssignableTo(t, anyIterable));
19209+ nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isTypeAssignableTo(t, anyIterable));
19210+ }
19211+ else {
19212+ arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType);
19213+ nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t));
19214+ }
1914319215 if (moreThanOneRealChildren) {
1914419216 if (arrayLikeTargetParts !== neverType) {
1914519217 const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal));
1914619218 const children = generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic);
19147- result = elaborateElementwise (children, realSource, arrayLikeTargetParts, relation, containingMessageChain, errorOutputContainer) || result;
19219+ result = elaborateIterableOrArrayLikeTargetElementwise (children, realSource, arrayLikeTargetParts, relation, containingMessageChain, errorOutputContainer) || result;
1914819220 }
1914919221 else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) {
1915019222 // arity mismatch
0 commit comments