@@ -8809,21 +8809,34 @@ namespace ts {
8809
8809
8810
8810
const type = getTypeOfSymbol(localOrExportSymbol);
8811
8811
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.
8812
8814
if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || isAssignmentTarget(node) || !declaration) {
8813
8815
return type;
8814
8816
}
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.
8816
8820
const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter;
8817
8821
const declarationContainer = getControlFlowContainer(declaration);
8818
8822
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.
8819
8826
while (flowContainer !== declarationContainer &&
8820
8827
(flowContainer.kind === SyntaxKind.FunctionExpression || flowContainer.kind === SyntaxKind.ArrowFunction) &&
8821
8828
(isReadonlySymbol(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) {
8822
8829
flowContainer = getControlFlowContainer(flowContainer);
8823
8830
}
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).
8824
8834
const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter ||
8825
8835
flowContainer !== declarationContainer || isInAmbientContext(declaration);
8826
8836
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.
8827
8840
if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
8828
8841
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
8829
8842
// Return the declared type to reduce follow-on errors
0 commit comments