@@ -79,6 +79,7 @@ namespace ts {
7979 getIndexTypeOfType,
8080 getBaseTypes,
8181 getReturnTypeOfSignature,
82+ getNonNullableType,
8283 getSymbolsInScope,
8384 getSymbolAtLocation,
8485 getShorthandAssignmentValueSymbol,
@@ -2884,6 +2885,10 @@ namespace ts {
28842885 return undefined;
28852886 }
28862887
2888+ function addOptionality(type: Type, optional: boolean): Type {
2889+ return strictNullChecks && optional ? addNullableKind(type, TypeFlags.Undefined) : type;
2890+ }
2891+
28872892 // Return the inferred type for a variable, parameter, or property declaration
28882893 function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
28892894 if (declaration.flags & NodeFlags.JavaScriptFile) {
@@ -2915,8 +2920,7 @@ namespace ts {
29152920
29162921 // Use type from type annotation if one is present
29172922 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);
29202924 }
29212925
29222926 if (declaration.kind === SyntaxKind.Parameter) {
@@ -2938,13 +2942,13 @@ namespace ts {
29382942 ? getContextuallyTypedThisType(func)
29392943 : getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
29402944 if (type) {
2941- return strictNullChecks && declaration.questionToken ? addNullableKind (type, TypeFlags.Undefined) : type ;
2945+ return addOptionality (type, /*optional*/ !!declaration.questionToken) ;
29422946 }
29432947 }
29442948
29452949 // Use the type of the initializer expression if one is present
29462950 if (declaration.initializer) {
2947- return checkExpressionCached(declaration.initializer);
2951+ return addOptionality( checkExpressionCached(declaration.initializer), /*optional*/ !!declaration.questionToken );
29482952 }
29492953
29502954 // If it is a short-hand property assignment, use the type of the identifier
@@ -3215,7 +3219,9 @@ namespace ts {
32153219 function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
32163220 const links = getSymbolLinks(symbol);
32173221 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;
32193225 }
32203226 return links.type;
32213227 }
@@ -7614,11 +7620,12 @@ namespace ts {
76147620 getInitialTypeOfBindingElement(<BindingElement>node);
76157621 }
76167622
7617- function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type ) {
7623+ function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean ) {
76187624 let key: string;
7619- if (!reference.flowNode || declaredType === initialType && !(declaredType.flags & TypeFlags.Narrowable)) {
7625+ if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
76207626 return declaredType;
76217627 }
7628+ const initialType = assumeInitialized ? declaredType : addNullableKind(declaredType, TypeFlags.Undefined);
76227629 const visitedFlowStart = visitedFlowCount;
76237630 const result = getTypeAtFlowNode(reference.flowNode);
76247631 visitedFlowCount = visitedFlowStart;
@@ -8092,11 +8099,11 @@ namespace ts {
80928099 return type;
80938100 }
80948101 const declaration = localOrExportSymbol.valueDeclaration;
8095- const defaultsToDeclaredType = !strictNullChecks || type.flags & TypeFlags.Any || !declaration ||
8102+ const assumeInitialized = !strictNullChecks || ( type.flags & TypeFlags.Any) !== 0 || !declaration ||
80968103 getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
80978104 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) {
81008107 error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
81018108 // Return the declared type to reduce follow-on errors
81028109 return type;
@@ -8344,7 +8351,7 @@ namespace ts {
83448351 if (isClassLike(container.parent)) {
83458352 const symbol = getSymbolOfNode(container.parent);
83468353 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 );
83488355 }
83498356
83508357 if (isInJavaScriptFile(node)) {
@@ -9919,7 +9926,8 @@ namespace ts {
99199926 }
99209927
99219928 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))) {
99239931 return propType;
99249932 }
99259933 const leftmostNode = getLeftmostIdentifierOrThis(node);
@@ -9936,7 +9944,7 @@ namespace ts {
99369944 return propType;
99379945 }
99389946 }
9939- return getFlowTypeOfReference(node, propType, propType );
9947+ return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true );
99409948 }
99419949
99429950 function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
@@ -13400,7 +13408,7 @@ namespace ts {
1340013408
1340113409 // Abstract methods can't have an implementation -- in particular, they don't need one.
1340213410 if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
13403- !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) {
13411+ !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken ) {
1340413412 reportImplementationExpectedError(lastSeenNonAmbientDeclaration);
1340513413 }
1340613414
@@ -18290,7 +18298,7 @@ namespace ts {
1829018298 }
1829118299
1829218300 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 )) {
1829418302 return true;
1829518303 }
1829618304 else if (node.body === undefined) {
@@ -18299,9 +18307,6 @@ namespace ts {
1829918307 }
1830018308
1830118309 if (isClassLike(node.parent)) {
18302- if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) {
18303- return true;
18304- }
1830518310 // Technically, computed properties in ambient contexts is disallowed
1830618311 // for property declarations and accessors too, not just methods.
1830718312 // However, property declarations disallow computed names in general,
@@ -18523,8 +18528,7 @@ namespace ts {
1852318528
1852418529 function checkGrammarProperty(node: PropertyDeclaration) {
1852518530 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)) {
1852818532 return true;
1852918533 }
1853018534 }
0 commit comments