Skip to content

Commit 0621f7e

Browse files
committed
Control flow typing for variables with null or undefined initializer
1 parent bd19f1d commit 0621f7e

File tree

2 files changed

+10
-4
lines changed

2 files changed

+10
-4
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3051,6 +3051,11 @@ namespace ts {
30513051
return undefined;
30523052
}
30533053

3054+
function isAutoVariableInitializer(initializer: Expression) {
3055+
let expr = initializer && skipParentheses(initializer);
3056+
return !expr || expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>expr) === undefinedSymbol;
3057+
}
3058+
30543059
function addOptionality(type: Type, optional: boolean): Type {
30553060
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
30563061
}
@@ -3090,9 +3095,10 @@ namespace ts {
30903095
}
30913096

30923097
// Use control flow type inference for non-ambient, non-exported var or let variables with no initializer
3098+
// or a 'null' or 'undefined' initializer.
30933099
if (declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
30943100
!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) &&
3095-
!declaration.initializer && !isInAmbientContext(declaration)) {
3101+
!isInAmbientContext(declaration) && isAutoVariableInitializer(declaration.initializer)) {
30963102
return autoType;
30973103
}
30983104

@@ -8965,7 +8971,7 @@ namespace ts {
89658971
if (isRightSideOfQualifiedNameOrPropertyAccess(location)) {
89668972
location = location.parent;
89678973
}
8968-
if (isExpression(location) && !isAssignmentTarget(location)) {
8974+
if (isPartOfExpression(location) && !isAssignmentTarget(location)) {
89698975
const type = checkExpression(<Expression>location);
89708976
if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) {
89718977
return type;
@@ -9146,7 +9152,7 @@ namespace ts {
91469152
if (type === autoType) {
91479153
if (flowType === autoType) {
91489154
if (compilerOptions.noImplicitAny) {
9149-
error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_any_and_is_referenced_in_a_nested_function, symbolToString(symbol));
9155+
error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_any_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol));
91509156
}
91519157
return anyType;
91529158
}

src/compiler/diagnosticMessages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2953,7 +2953,7 @@
29532953
"category": "Error",
29542954
"code": 7033
29552955
},
2956-
"Variable '{0}' implicitly has type 'any' and is referenced in a nested function.": {
2956+
"Variable '{0}' implicitly has type 'any' in some locations where its type cannot be determined.": {
29572957
"category": "Error",
29582958
"code": 7034
29592959
},

0 commit comments

Comments
 (0)