@@ -119,6 +119,7 @@ namespace ts {
119
119
const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
120
120
121
121
const anyType = createIntrinsicType(TypeFlags.Any, "any");
122
+ const autoType = createIntrinsicType(TypeFlags.Any, "any");
122
123
const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
123
124
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
124
125
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
@@ -3086,6 +3087,13 @@ namespace ts {
3086
3087
return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality);
3087
3088
}
3088
3089
3090
+ // Use control flow type inference for non-ambient, non-exported var or let variables with no initializer
3091
+ if (declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
3092
+ !(getCombinedNodeFlags(declaration) & NodeFlags.Const) && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) &&
3093
+ !declaration.initializer && !isInAmbientContext(declaration)) {
3094
+ return autoType;
3095
+ }
3096
+
3089
3097
if (declaration.kind === SyntaxKind.Parameter) {
3090
3098
const func = <FunctionLikeDeclaration>declaration.parent;
3091
3099
// For a parameter of a set accessor, use the type of the get accessor if one is present
@@ -8352,7 +8360,9 @@ namespace ts {
8352
8360
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
8353
8361
return declaredType;
8354
8362
}
8355
- const initialType = assumeInitialized ? declaredType : includeFalsyTypes(declaredType, TypeFlags.Undefined);
8363
+ const initialType = assumeInitialized ? declaredType :
8364
+ declaredType === autoType ? undefinedType :
8365
+ includeFalsyTypes(declaredType, TypeFlags.Undefined);
8356
8366
const visitedFlowStart = visitedFlowCount;
8357
8367
const result = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
8358
8368
visitedFlowCount = visitedFlowStart;
@@ -8430,8 +8440,8 @@ namespace ts {
8430
8440
const flowType = getTypeAtFlowNode(flow.antecedent);
8431
8441
return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType));
8432
8442
}
8433
- return declaredType.flags & TypeFlags.Union ?
8434
- getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node)) :
8443
+ return declaredType === autoType ? getBaseTypeOfLiteralType(getInitialOrAssignedType(node)) :
8444
+ declaredType.flags & TypeFlags.Union ? getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node)) :
8435
8445
declaredType;
8436
8446
}
8437
8447
// We didn't have a direct match. However, if the reference is a dotted name, this
@@ -9042,13 +9052,22 @@ namespace ts {
9042
9052
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
9043
9053
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
9044
9054
// declaration container are the same).
9045
- const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter ||
9046
- isOuterVariable || isInAmbientContext(declaration);
9055
+ const assumeInitialized = isParameter || isOuterVariable ||
9056
+ type !== autoType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0) ||
9057
+ isInAmbientContext(declaration);
9047
9058
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
9048
9059
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
9049
9060
// from declaration to use, and when the variable's declared type doesn't include undefined but the
9050
9061
// control flow based type does include undefined.
9051
- if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
9062
+ if (type === autoType) {
9063
+ if (flowType === autoType) {
9064
+ if (compilerOptions.noImplicitAny) {
9065
+ error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_any_and_is_referenced_in_a_nested_function, symbolToString(symbol));
9066
+ }
9067
+ return anyType;
9068
+ }
9069
+ }
9070
+ else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
9052
9071
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
9053
9072
// Return the declared type to reduce follow-on errors
9054
9073
return type;
0 commit comments