@@ -79,6 +79,7 @@ namespace ts {
79
79
getIndexTypeOfType,
80
80
getBaseTypes,
81
81
getReturnTypeOfSignature,
82
+ getNonNullableType,
82
83
getSymbolsInScope,
83
84
getSymbolAtLocation,
84
85
getShorthandAssignmentValueSymbol,
@@ -2884,6 +2885,10 @@ namespace ts {
2884
2885
return undefined;
2885
2886
}
2886
2887
2888
+ function addOptionality(type: Type, optional: boolean): Type {
2889
+ return strictNullChecks && optional ? addNullableKind(type, TypeFlags.Undefined) : type;
2890
+ }
2891
+
2887
2892
// Return the inferred type for a variable, parameter, or property declaration
2888
2893
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
2889
2894
if (declaration.flags & NodeFlags.JavaScriptFile) {
@@ -2915,8 +2920,7 @@ namespace ts {
2915
2920
2916
2921
// Use type from type annotation if one is present
2917
2922
if (declaration.type) {
2918
- const type = getTypeFromTypeNode(declaration.type);
2919
- return strictNullChecks && declaration.questionToken ? addNullableKind(type, TypeFlags.Undefined) : type;
2923
+ return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ !!declaration.questionToken);
2920
2924
}
2921
2925
2922
2926
if (declaration.kind === SyntaxKind.Parameter) {
@@ -2938,13 +2942,13 @@ namespace ts {
2938
2942
? getContextuallyTypedThisType(func)
2939
2943
: getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
2940
2944
if (type) {
2941
- return strictNullChecks && declaration.questionToken ? addNullableKind (type, TypeFlags.Undefined) : type ;
2945
+ return addOptionality (type, /*optional*/ !!declaration.questionToken) ;
2942
2946
}
2943
2947
}
2944
2948
2945
2949
// Use the type of the initializer expression if one is present
2946
2950
if (declaration.initializer) {
2947
- return checkExpressionCached(declaration.initializer);
2951
+ return addOptionality( checkExpressionCached(declaration.initializer), /*optional*/ !!declaration.questionToken );
2948
2952
}
2949
2953
2950
2954
// If it is a short-hand property assignment, use the type of the identifier
@@ -3215,7 +3219,9 @@ namespace ts {
3215
3219
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
3216
3220
const links = getSymbolLinks(symbol);
3217
3221
if (!links.type) {
3218
- links.type = createObjectType(TypeFlags.Anonymous, symbol);
3222
+ const type = createObjectType(TypeFlags.Anonymous, symbol);
3223
+ links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ?
3224
+ addNullableKind(type, TypeFlags.Undefined) : type;
3219
3225
}
3220
3226
return links.type;
3221
3227
}
@@ -7614,11 +7620,12 @@ namespace ts {
7614
7620
getInitialTypeOfBindingElement(<BindingElement>node);
7615
7621
}
7616
7622
7617
- function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type ) {
7623
+ function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean ) {
7618
7624
let key: string;
7619
- if (!reference.flowNode || declaredType === initialType && !(declaredType.flags & TypeFlags.Narrowable)) {
7625
+ if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
7620
7626
return declaredType;
7621
7627
}
7628
+ const initialType = assumeInitialized ? declaredType : addNullableKind(declaredType, TypeFlags.Undefined);
7622
7629
const visitedFlowStart = visitedFlowCount;
7623
7630
const result = getTypeAtFlowNode(reference.flowNode);
7624
7631
visitedFlowCount = visitedFlowStart;
@@ -8092,11 +8099,11 @@ namespace ts {
8092
8099
return type;
8093
8100
}
8094
8101
const declaration = localOrExportSymbol.valueDeclaration;
8095
- const defaultsToDeclaredType = !strictNullChecks || type.flags & TypeFlags.Any || !declaration ||
8102
+ const assumeInitialized = !strictNullChecks || ( type.flags & TypeFlags.Any) !== 0 || !declaration ||
8096
8103
getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
8097
8104
getContainingFunctionOrModule(declaration) !== getContainingFunctionOrModule(node);
8098
- const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : addNullableKind(type, TypeFlags.Undefined) );
8099
- if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
8105
+ const flowType = getFlowTypeOfReference(node, type, assumeInitialized );
8106
+ if (!assumeInitialized && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
8100
8107
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
8101
8108
// Return the declared type to reduce follow-on errors
8102
8109
return type;
@@ -8344,7 +8351,7 @@ namespace ts {
8344
8351
if (isClassLike(container.parent)) {
8345
8352
const symbol = getSymbolOfNode(container.parent);
8346
8353
const type = container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
8347
- return getFlowTypeOfReference(node, type, type );
8354
+ return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true );
8348
8355
}
8349
8356
8350
8357
if (isInJavaScriptFile(node)) {
@@ -9919,7 +9926,8 @@ namespace ts {
9919
9926
}
9920
9927
9921
9928
const propType = getTypeOfSymbol(prop);
9922
- if (node.kind !== SyntaxKind.PropertyAccessExpression || !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) || isAssignmentTarget(node)) {
9929
+ if (node.kind !== SyntaxKind.PropertyAccessExpression || isAssignmentTarget(node) ||
9930
+ !(propType.flags & TypeFlags.Union) && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor))) {
9923
9931
return propType;
9924
9932
}
9925
9933
const leftmostNode = getLeftmostIdentifierOrThis(node);
@@ -9936,7 +9944,7 @@ namespace ts {
9936
9944
return propType;
9937
9945
}
9938
9946
}
9939
- return getFlowTypeOfReference(node, propType, propType );
9947
+ return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true );
9940
9948
}
9941
9949
9942
9950
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
@@ -13400,7 +13408,7 @@ namespace ts {
13400
13408
13401
13409
// Abstract methods can't have an implementation -- in particular, they don't need one.
13402
13410
if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
13403
- !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) {
13411
+ !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken ) {
13404
13412
reportImplementationExpectedError(lastSeenNonAmbientDeclaration);
13405
13413
}
13406
13414
@@ -18290,7 +18298,7 @@ namespace ts {
18290
18298
}
18291
18299
18292
18300
if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) {
18293
- if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional )) {
18301
+ if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional )) {
18294
18302
return true;
18295
18303
}
18296
18304
else if (node.body === undefined) {
@@ -18299,9 +18307,6 @@ namespace ts {
18299
18307
}
18300
18308
18301
18309
if (isClassLike(node.parent)) {
18302
- if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) {
18303
- return true;
18304
- }
18305
18310
// Technically, computed properties in ambient contexts is disallowed
18306
18311
// for property declarations and accessors too, not just methods.
18307
18312
// However, property declarations disallow computed names in general,
@@ -18523,8 +18528,7 @@ namespace ts {
18523
18528
18524
18529
function checkGrammarProperty(node: PropertyDeclaration) {
18525
18530
if (isClassLike(node.parent)) {
18526
- if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional) ||
18527
- checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol)) {
18531
+ if (checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol)) {
18528
18532
return true;
18529
18533
}
18530
18534
}
0 commit comments