@@ -8524,9 +8524,11 @@ namespace ts {
8524
8524
}
8525
8525
8526
8526
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);
8530
8532
}
8531
8533
8532
8534
// We perform subtype reduction upon obtaining the final array type from an evolving array type.
@@ -8564,26 +8566,22 @@ namespace ts {
8564
8566
getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction);
8565
8567
}
8566
8568
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) {
8578
8572
const root = getReferenceRoot(node);
8579
8573
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 &&
8581
8578
(<ElementAccessExpression>parent).expression === root &&
8582
8579
parent.parent.kind === SyntaxKind.BinaryExpression &&
8583
8580
(<BinaryExpression>parent.parent).operatorToken.kind === SyntaxKind.EqualsToken &&
8584
8581
(<BinaryExpression>parent.parent).left === parent &&
8585
8582
!isAssignmentTarget(parent.parent) &&
8586
8583
isTypeAnyOrAllConstituentTypesHaveKind(checkExpression((<ElementAccessExpression>parent).argumentExpression), TypeFlags.NumberLike | TypeFlags.Undefined);
8584
+ return isLengthPushOrUnshift || isElementAssignment;
8587
8585
}
8588
8586
8589
8587
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
@@ -8597,11 +8595,11 @@ namespace ts {
8597
8595
const visitedFlowStart = visitedFlowCount;
8598
8596
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
8599
8597
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);
8605
8603
if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
8606
8604
return declaredType;
8607
8605
}
@@ -9355,12 +9353,12 @@ namespace ts {
9355
9353
// from declaration to use, and when the variable's declared type doesn't include undefined but the
9356
9354
// control flow based type does include undefined.
9357
9355
if (type === autoType || type === autoArrayType) {
9358
- if (flowType === type ) {
9356
+ if (flowType === autoType || flowType === autoArrayType ) {
9359
9357
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 ));
9362
9360
}
9363
- return convertAutoToAny(type );
9361
+ return convertAutoToAny(flowType );
9364
9362
}
9365
9363
}
9366
9364
else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
0 commit comments