@@ -8809,21 +8809,34 @@ namespace ts {
88098809
88108810 const type = getTypeOfSymbol(localOrExportSymbol);
88118811 const declaration = localOrExportSymbol.valueDeclaration;
8812+ // We only narrow variables and parameters occurring in a non-assignment position. For all other
8813+ // entities we simply return the declared type.
88128814 if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || isAssignmentTarget(node) || !declaration) {
88138815 return type;
88148816 }
8815-
8817+ // The declaration container is the innermost function that encloses the declaration of the variable
8818+ // or parameter. The flow container is the innermost function starting with which we analyze the control
8819+ // flow graph to determine the control flow based type.
88168820 const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter;
88178821 const declarationContainer = getControlFlowContainer(declaration);
88188822 let flowContainer = getControlFlowContainer(node);
8823+ // When the control flow originates in a function expression or arrow function and we are referencing
8824+ // a const variable or parameter from an outer function, we extend the origin of the control flow
8825+ // analysis to include the immediately enclosing function.
88198826 while (flowContainer !== declarationContainer &&
88208827 (flowContainer.kind === SyntaxKind.FunctionExpression || flowContainer.kind === SyntaxKind.ArrowFunction) &&
88218828 (isReadonlySymbol(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) {
88228829 flowContainer = getControlFlowContainer(flowContainer);
88238830 }
8831+ // We only look for uninitialized variables in strict null checking mode, and only when we can analyze
8832+ // the entire control flow graph from the variable's declaration (i.e. when the flow container and
8833+ // declaration container are the same).
88248834 const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter ||
88258835 flowContainer !== declarationContainer || isInAmbientContext(declaration);
88268836 const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
8837+ // A variable is considered uninitialized when it is possible to analyze the entire control flow graph
8838+ // from declaration to use, and when the variable's declared type doesn't include undefined but the
8839+ // control flow based type does include undefined.
88278840 if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
88288841 error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
88298842 // Return the declared type to reduce follow-on errors
0 commit comments