@@ -19072,6 +19072,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19072
19072
return reportedError;
19073
19073
}
19074
19074
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
+
19075
19137
function *generateJsxAttributes(node: JsxAttributes): ElaborationIterator {
19076
19138
if (!length(node.properties)) return;
19077
19139
for (const prop of node.properties) {
@@ -19138,13 +19200,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19138
19200
return result;
19139
19201
}
19140
19202
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
+ }
19143
19215
if (moreThanOneRealChildren) {
19144
19216
if (arrayLikeTargetParts !== neverType) {
19145
19217
const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal));
19146
19218
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;
19148
19220
}
19149
19221
else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) {
19150
19222
// arity mismatch
0 commit comments