@@ -3368,16 +3368,6 @@ namespace ts {
3368
3368
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
3369
3369
}
3370
3370
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
-
3381
3371
// Return the inferred type for a variable, parameter, or property declaration
3382
3372
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
3383
3373
if (declaration.flags & NodeFlags.JavaScriptFile) {
@@ -3412,7 +3402,7 @@ namespace ts {
3412
3402
3413
3403
// Use type from type annotation if one is present
3414
3404
if (declaration.type) {
3415
- const declaredType = removeOptionalityFromAnnotation( getTypeFromTypeNode(declaration.type), declaration );
3405
+ const declaredType = getTypeFromTypeNode(declaration.type);
3416
3406
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
3417
3407
}
3418
3408
@@ -10248,14 +10238,12 @@ namespace ts {
10248
10238
return false;
10249
10239
}
10250
10240
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) {
10252
10246
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);
10259
10247
const visitedFlowStart = visitedFlowCount;
10260
10248
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
10261
10249
visitedFlowCount = visitedFlowStart;
@@ -10934,6 +10922,16 @@ namespace ts {
10934
10922
return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 && getTypeOfSymbol(symbol) !== autoArrayType;
10935
10923
}
10936
10924
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
+
10937
10935
function checkIdentifier(node: Identifier): Type {
10938
10936
const symbol = getResolvedSymbol(node);
10939
10937
if (symbol === unknownSymbol) {
@@ -11052,7 +11050,10 @@ namespace ts {
11052
11050
const assumeInitialized = isParameter || isOuterVariable ||
11053
11051
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node)) ||
11054
11052
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;
11056
11057
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
11057
11058
// from declaration to use, and when the variable's declared type doesn't include undefined but the
11058
11059
// control flow based type does include undefined.
@@ -11318,7 +11319,7 @@ namespace ts {
11318
11319
if (isClassLike(container.parent)) {
11319
11320
const symbol = getSymbolOfNode(container.parent);
11320
11321
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 ;
11322
11323
}
11323
11324
11324
11325
if (isInJavaScriptFile(node)) {
@@ -13309,7 +13310,7 @@ namespace ts {
13309
13310
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
13310
13311
return propType;
13311
13312
}
13312
- const flowType = getFlowTypeOfReference (node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined) ;
13313
+ const flowType = isFlowNarrowable (node, propType) ? getFlowTypeOfReference(node, propType) : propType ;
13313
13314
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
13314
13315
}
13315
13316
0 commit comments