@@ -3368,16 +3368,6 @@ namespace ts {
33683368 return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
33693369 }
33703370
3371- /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
3372- function removeOptionalityFromAnnotation(annotatedType: Type, declaration: VariableLikeDeclaration): Type {
3373- const annotationIncludesUndefined = strictNullChecks &&
3374- declaration.kind === SyntaxKind.Parameter &&
3375- declaration.initializer &&
3376- getFalsyFlags(annotatedType) & TypeFlags.Undefined &&
3377- !(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
3378- return annotationIncludesUndefined ? getNonNullableType(annotatedType) : annotatedType;
3379- }
3380-
33813371 // Return the inferred type for a variable, parameter, or property declaration
33823372 function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
33833373 if (declaration.flags & NodeFlags.JavaScriptFile) {
@@ -3412,7 +3402,7 @@ namespace ts {
34123402
34133403 // Use type from type annotation if one is present
34143404 if (declaration.type) {
3415- const declaredType = removeOptionalityFromAnnotation( getTypeFromTypeNode(declaration.type), declaration );
3405+ const declaredType = getTypeFromTypeNode(declaration.type);
34163406 return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
34173407 }
34183408
@@ -10248,14 +10238,12 @@ namespace ts {
1024810238 return false;
1024910239 }
1025010240
10251- function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
10241+ function isFlowNarrowable(reference: Node, type: Type, couldBeUninitialized?: boolean) {
10242+ return reference.flowNode && (type.flags & TypeFlags.Narrowable || couldBeUninitialized);
10243+ }
10244+
10245+ function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node) {
1025210246 let key: string;
10253- if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
10254- return declaredType;
10255- }
10256- const initialType = assumeInitialized ? declaredType :
10257- declaredType === autoType || declaredType === autoArrayType ? undefinedType :
10258- includeFalsyTypes(declaredType, TypeFlags.Undefined);
1025910247 const visitedFlowStart = visitedFlowCount;
1026010248 const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
1026110249 visitedFlowCount = visitedFlowStart;
@@ -10934,6 +10922,16 @@ namespace ts {
1093410922 return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 && getTypeOfSymbol(symbol) !== autoArrayType;
1093510923 }
1093610924
10925+ /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
10926+ function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type {
10927+ const annotationIncludesUndefined = strictNullChecks &&
10928+ declaration.kind === SyntaxKind.Parameter &&
10929+ declaration.initializer &&
10930+ getFalsyFlags(declaredType) & TypeFlags.Undefined &&
10931+ !(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
10932+ return annotationIncludesUndefined ? getNonNullableType(declaredType) : declaredType;
10933+ }
10934+
1093710935 function checkIdentifier(node: Identifier): Type {
1093810936 const symbol = getResolvedSymbol(node);
1093910937 if (symbol === unknownSymbol) {
@@ -11052,7 +11050,10 @@ namespace ts {
1105211050 const assumeInitialized = isParameter || isOuterVariable ||
1105311051 type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node)) ||
1105411052 isInAmbientContext(declaration);
11055- const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
11053+ const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) :
11054+ type === autoType || type === autoArrayType ? undefinedType :
11055+ includeFalsyTypes(type, TypeFlags.Undefined);
11056+ const flowType = isFlowNarrowable(node, type, !assumeInitialized) ? getFlowTypeOfReference(node, type, initialType, flowContainer) : type;
1105611057 // A variable is considered uninitialized when it is possible to analyze the entire control flow graph
1105711058 // from declaration to use, and when the variable's declared type doesn't include undefined but the
1105811059 // control flow based type does include undefined.
@@ -11318,7 +11319,7 @@ namespace ts {
1131811319 if (isClassLike(container.parent)) {
1131911320 const symbol = getSymbolOfNode(container.parent);
1132011321 const type = hasModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
11321- return getFlowTypeOfReference (node, type, /*assumeInitialized*/ true, /*flowContainer*/ undefined) ;
11322+ return isFlowNarrowable (node, type) ? getFlowTypeOfReference(node, type) : type ;
1132211323 }
1132311324
1132411325 if (isInJavaScriptFile(node)) {
@@ -13309,7 +13310,7 @@ namespace ts {
1330913310 !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
1331013311 return propType;
1331113312 }
13312- const flowType = getFlowTypeOfReference (node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined) ;
13313+ const flowType = isFlowNarrowable (node, propType) ? getFlowTypeOfReference(node, propType) : propType ;
1331313314 return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
1331413315 }
1331513316
0 commit comments