@@ -20503,7 +20503,45 @@ namespace ts {
20503
20503
AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) :
20504
20504
AccessFlags.None;
20505
20505
const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, node, accessFlags) || errorType;
20506
- return checkIndexedAccessIndexType(indexedAccessType, node);
20506
+ const prop = indexedAccessType.symbol;
20507
+
20508
+ // Only compute control flow type if this is a property access expression that isn't an
20509
+ // assignment target, and the referenced property was declared as a variable, property,
20510
+ // accessor, or optional method.
20511
+ // TODO: This probably doesn't handle element access expressions
20512
+ const assignmentKind = getAssignmentTargetKind(node);
20513
+ if (node.kind !== SyntaxKind.ElementAccessExpression ||
20514
+ assignmentKind === AssignmentKind.Definite ||
20515
+ prop && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && indexedAccessType.flags & TypeFlags.Union)) {
20516
+ return checkIndexedAccessIndexType(indexedAccessType, node);
20517
+ }
20518
+ // If strict null checks and strict property initialization checks are enabled, if we have
20519
+ // a this.xxx property access, if the property is an instance property without an initializer,
20520
+ // and if we are in a constructor of the same class as the property declaration, assume that
20521
+ // the property is uninitialized at the top of the control flow.
20522
+ let assumeUninitialized = false;
20523
+ if (strictNullChecks && strictPropertyInitialization && node.expression.kind === SyntaxKind.ThisKeyword) {
20524
+ const declaration = prop && prop.valueDeclaration;
20525
+ if (declaration && isInstancePropertyWithoutInitializer(declaration)) {
20526
+ const flowContainer = getControlFlowContainer(node);
20527
+ if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent) {
20528
+ assumeUninitialized = true;
20529
+ }
20530
+ }
20531
+ }
20532
+ else if (strictNullChecks && prop && prop.valueDeclaration &&
20533
+ isPropertyAccessExpression(prop.valueDeclaration) &&
20534
+ getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) &&
20535
+ getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration)) {
20536
+ assumeUninitialized = true;
20537
+ }
20538
+ const flowType = getFlowTypeOfReference(node, indexedAccessType, assumeUninitialized ? getOptionalType(indexedAccessType) : indexedAccessType);
20539
+ if (assumeUninitialized && !(getFalsyFlags(indexedAccessType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
20540
+ error(indexExpression, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217
20541
+ // Return the declared type to reduce follow-on errors
20542
+ return indexedAccessType;
20543
+ }
20544
+ return checkIndexedAccessIndexType(assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType, node);
20507
20545
}
20508
20546
20509
20547
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
0 commit comments