@@ -8524,9 +8524,11 @@ namespace ts {
85248524 }
85258525
85268526 function createFinalArrayType(elementType: Type) {
8527- return createArrayType(elementType !== neverType ?
8528- elementType.flags & TypeFlags.Union ? getUnionType((<UnionType>elementType).types, /*subtypeReduction*/ true) : elementType :
8529- strictNullChecks ? neverType : undefinedWideningType);
8527+ return elementType.flags & TypeFlags.Never ?
8528+ autoArrayType :
8529+ createArrayType(elementType.flags & TypeFlags.Union ?
8530+ getUnionType((<UnionType>elementType).types, /*subtypeReduction*/ true) :
8531+ elementType);
85308532 }
85318533
85328534 // We perform subtype reduction upon obtaining the final array type from an evolving array type.
@@ -8564,26 +8566,22 @@ namespace ts {
85648566 getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction);
85658567 }
85668568
8567- // Return true if the given node is 'x' in an 'x.push(value)' or 'x.unshift(value)' operation.
8568- function isPushOrUnshiftCallTarget(node: Node) {
8569- const parent = getReferenceRoot(node).parent;
8570- return parent.kind === SyntaxKind.PropertyAccessExpression &&
8571- parent.parent.kind === SyntaxKind.CallExpression &&
8572- isPushOrUnshiftIdentifier((<PropertyAccessExpression>parent).name);
8573- }
8574-
8575- // Return true if the given node is 'x' in an 'x[n] = value' operation, where 'n' is an
8576- // expression of type any, undefined, or a number-like type.
8577- function isElementAssignmentTarget(node: Node) {
8569+ // Return true if the given node is 'x' in an 'x.length', x.push(value)', 'x.unshift(value)' or
8570+ // 'x[n] = value' operation, where 'n' is an expression of type any, undefined, or a number-like type.
8571+ function isEvolvingArrayOperationTarget(node: Node) {
85788572 const root = getReferenceRoot(node);
85798573 const parent = root.parent;
8580- return parent.kind === SyntaxKind.ElementAccessExpression &&
8574+ const isLengthPushOrUnshift = parent.kind === SyntaxKind.PropertyAccessExpression && (
8575+ (<PropertyAccessExpression>parent).name.text === "length" ||
8576+ parent.parent.kind === SyntaxKind.CallExpression && isPushOrUnshiftIdentifier((<PropertyAccessExpression>parent).name));
8577+ const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression &&
85818578 (<ElementAccessExpression>parent).expression === root &&
85828579 parent.parent.kind === SyntaxKind.BinaryExpression &&
85838580 (<BinaryExpression>parent.parent).operatorToken.kind === SyntaxKind.EqualsToken &&
85848581 (<BinaryExpression>parent.parent).left === parent &&
85858582 !isAssignmentTarget(parent.parent) &&
85868583 isTypeAnyOrAllConstituentTypesHaveKind(checkExpression((<ElementAccessExpression>parent).argumentExpression), TypeFlags.NumberLike | TypeFlags.Undefined);
8584+ return isLengthPushOrUnshift || isElementAssignment;
85878585 }
85888586
85898587 function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
@@ -8597,11 +8595,11 @@ namespace ts {
85978595 const visitedFlowStart = visitedFlowCount;
85988596 const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
85998597 visitedFlowCount = visitedFlowStart;
8600- // When the reference is 'x' in an 'x.push(value)' or ' x[n] = value' operation, we give type
8601- // 'any[]' to 'x' instead of using the type determined by control flow analysis such that new
8602- // element types are not considered errors.
8603- const isEvolvingArrayInferenceTarget = isEvolvingArrayType(evolvedType) && (isPushOrUnshiftCallTarget(reference) || isElementAssignmentTarget(reference));
8604- const resultType = isEvolvingArrayInferenceTarget ? anyArrayType : finalizeEvolvingArrayType(evolvedType);
8598+ // When the reference is 'x' in an 'x.length', 'x. push(value)', 'x.unshift(value)' or x[n] = value' operation,
8599+ // we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations
8600+ // on empty arrays are possible without implicit any errors and new element types can be inferred without
8601+ // type mismatch errors.
8602+ const resultType = isEvolvingArrayType(evolvedType) && isEvolvingArrayOperationTarget(reference) ? anyArrayType : finalizeEvolvingArrayType(evolvedType);
86058603 if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
86068604 return declaredType;
86078605 }
@@ -9355,12 +9353,12 @@ namespace ts {
93559353 // from declaration to use, and when the variable's declared type doesn't include undefined but the
93569354 // control flow based type does include undefined.
93579355 if (type === autoType || type === autoArrayType) {
9358- if (flowType === type ) {
9356+ if (flowType === autoType || flowType === autoArrayType ) {
93599357 if (compilerOptions.noImplicitAny) {
9360- error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(type ));
9361- error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(type ));
9358+ error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType ));
9359+ error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType ));
93629360 }
9363- return convertAutoToAny(type );
9361+ return convertAutoToAny(flowType );
93649362 }
93659363 }
93669364 else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
0 commit comments