@@ -120,6 +120,7 @@ namespace ts {
120
120
const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
121
121
122
122
const anyType = createIntrinsicType(TypeFlags.Any, "any");
123
+ const autoType = createIntrinsicType(TypeFlags.Any, "any");
123
124
const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
124
125
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
125
126
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
@@ -3056,6 +3057,11 @@ namespace ts {
3056
3057
return undefined;
3057
3058
}
3058
3059
3060
+ function isAutoVariableInitializer(initializer: Expression) {
3061
+ const expr = initializer && skipParentheses(initializer);
3062
+ return !expr || expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>expr) === undefinedSymbol;
3063
+ }
3064
+
3059
3065
function addOptionality(type: Type, optional: boolean): Type {
3060
3066
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
3061
3067
}
@@ -3094,6 +3100,14 @@ namespace ts {
3094
3100
return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality);
3095
3101
}
3096
3102
3103
+ // Use control flow type inference for non-ambient, non-exported var or let variables with no initializer
3104
+ // or a 'null' or 'undefined' initializer.
3105
+ if (declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
3106
+ !(getCombinedNodeFlags(declaration) & NodeFlags.Const) && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) &&
3107
+ !isInAmbientContext(declaration) && isAutoVariableInitializer(declaration.initializer)) {
3108
+ return autoType;
3109
+ }
3110
+
3097
3111
if (declaration.kind === SyntaxKind.Parameter) {
3098
3112
const func = <FunctionLikeDeclaration>declaration.parent;
3099
3113
// For a parameter of a set accessor, use the type of the get accessor if one is present
@@ -8460,7 +8474,9 @@ namespace ts {
8460
8474
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
8461
8475
return declaredType;
8462
8476
}
8463
- const initialType = assumeInitialized ? declaredType : includeFalsyTypes(declaredType, TypeFlags.Undefined);
8477
+ const initialType = assumeInitialized ? declaredType :
8478
+ declaredType === autoType ? undefinedType :
8479
+ includeFalsyTypes(declaredType, TypeFlags.Undefined);
8464
8480
const visitedFlowStart = visitedFlowCount;
8465
8481
const result = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
8466
8482
visitedFlowCount = visitedFlowStart;
@@ -8534,9 +8550,12 @@ namespace ts {
8534
8550
// Assignments only narrow the computed type if the declared type is a union type. Thus, we
8535
8551
// only need to evaluate the assigned type if the declared type is a union type.
8536
8552
if (isMatchingReference(reference, node)) {
8537
- const isIncrementOrDecrement = node.parent.kind === SyntaxKind.PrefixUnaryExpression || node.parent.kind === SyntaxKind.PostfixUnaryExpression;
8538
- return declaredType.flags & TypeFlags.Union && !isIncrementOrDecrement ?
8539
- getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node)) :
8553
+ if (node.parent.kind === SyntaxKind.PrefixUnaryExpression || node.parent.kind === SyntaxKind.PostfixUnaryExpression) {
8554
+ const flowType = getTypeAtFlowNode(flow.antecedent);
8555
+ return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType));
8556
+ }
8557
+ return declaredType === autoType ? getBaseTypeOfLiteralType(getInitialOrAssignedType(node)) :
8558
+ declaredType.flags & TypeFlags.Union ? getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node)) :
8540
8559
declaredType;
8541
8560
}
8542
8561
// We didn't have a direct match. However, if the reference is a dotted name, this
@@ -8980,7 +8999,7 @@ namespace ts {
8980
8999
if (isRightSideOfQualifiedNameOrPropertyAccess(location)) {
8981
9000
location = location.parent;
8982
9001
}
8983
- if (isExpression (location) && !isAssignmentTarget(location)) {
9002
+ if (isPartOfExpression (location) && !isAssignmentTarget(location)) {
8984
9003
const type = checkExpression(<Expression>location);
8985
9004
if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) {
8986
9005
return type;
@@ -9151,13 +9170,23 @@ namespace ts {
9151
9170
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
9152
9171
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
9153
9172
// declaration container are the same).
9154
- const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter ||
9155
- isOuterVariable || isInAmbientContext(declaration);
9173
+ const assumeInitialized = isParameter || isOuterVariable ||
9174
+ type !== autoType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0) ||
9175
+ isInAmbientContext(declaration);
9156
9176
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
9157
9177
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
9158
9178
// from declaration to use, and when the variable's declared type doesn't include undefined but the
9159
9179
// control flow based type does include undefined.
9160
- if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
9180
+ if (type === autoType) {
9181
+ if (flowType === autoType) {
9182
+ if (compilerOptions.noImplicitAny) {
9183
+ error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_any_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol));
9184
+ error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(anyType));
9185
+ }
9186
+ return anyType;
9187
+ }
9188
+ }
9189
+ else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
9161
9190
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
9162
9191
// Return the declared type to reduce follow-on errors
9163
9192
return type;
@@ -15906,6 +15935,10 @@ namespace ts {
15906
15935
}
15907
15936
}
15908
15937
15938
+ function convertAutoToAny(type: Type) {
15939
+ return type === autoType ? anyType : type;
15940
+ }
15941
+
15909
15942
// Check variable, parameter, or property declaration
15910
15943
function checkVariableLikeDeclaration(node: VariableLikeDeclaration) {
15911
15944
checkDecorators(node);
@@ -15956,7 +15989,7 @@ namespace ts {
15956
15989
return;
15957
15990
}
15958
15991
const symbol = getSymbolOfNode(node);
15959
- const type = getTypeOfVariableOrParameterOrProperty(symbol);
15992
+ const type = convertAutoToAny( getTypeOfVariableOrParameterOrProperty(symbol) );
15960
15993
if (node === symbol.valueDeclaration) {
15961
15994
// Node is the primary declaration of the symbol, just validate the initializer
15962
15995
// Don't validate for-in initializer as it is already an error
@@ -15968,7 +16001,7 @@ namespace ts {
15968
16001
else {
15969
16002
// Node is a secondary declaration, check that type is identical to primary declaration and check that
15970
16003
// initializer is consistent with type associated with the node
15971
- const declarationType = getWidenedTypeForVariableLikeDeclaration(node);
16004
+ const declarationType = convertAutoToAny( getWidenedTypeForVariableLikeDeclaration(node) );
15972
16005
if (type !== unknownType && declarationType !== unknownType && !isTypeIdenticalTo(type, declarationType)) {
15973
16006
error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(type), typeToString(declarationType));
15974
16007
}
0 commit comments