@@ -26743,7 +26743,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2674326743 if (
2674426744 isOrContainsMatchingReference(reference, argument)
2674526745 || optionalChainContainsReference(argument, reference)
26746- || isAccessExpression (argument) && isMatchingReference(reference, argument.expression )
26746+ || getCandidateDiscriminantPropertyAccess (argument, reference )
2674726747 ) {
2674826748 return true;
2674926749 }
@@ -26758,6 +26758,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2675826758 return false;
2675926759 }
2676026760
26761+ function getCandidateDiscriminantPropertyAccess(expr: Expression, reference: Node) {
26762+ if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) {
26763+ // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in
26764+ // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or
26765+ // parameter declared in the same parameter list is a candidate.
26766+ if (isIdentifier(expr)) {
26767+ const symbol = getResolvedSymbol(expr);
26768+ const declaration = symbol.valueDeclaration;
26769+ if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) {
26770+ return declaration;
26771+ }
26772+ }
26773+ }
26774+ else if (isAccessExpression(expr)) {
26775+ // An access expression is a candidate if the reference matches the left hand expression.
26776+ if (isMatchingReference(reference, expr.expression)) {
26777+ return expr;
26778+ }
26779+ }
26780+ else if (isIdentifier(expr)) {
26781+ const symbol = getResolvedSymbol(expr);
26782+ if (isConstantVariable(symbol)) {
26783+ const declaration = symbol.valueDeclaration!;
26784+ // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind'
26785+ if (
26786+ isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) &&
26787+ isMatchingReference(reference, declaration.initializer.expression)
26788+ ) {
26789+ return declaration.initializer;
26790+ }
26791+ // Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind'
26792+ if (isBindingElement(declaration) && !declaration.initializer) {
26793+ const parent = declaration.parent.parent;
26794+ if (
26795+ isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) &&
26796+ isMatchingReference(reference, parent.initializer)
26797+ ) {
26798+ return declaration;
26799+ }
26800+ }
26801+ }
26802+ }
26803+ return undefined;
26804+ }
26805+
2676126806 function getFlowNodeId(flow: FlowNode): number {
2676226807 if (!flow.id || flow.id < 0) {
2676326808 flow.id = nextFlowId;
@@ -28114,57 +28159,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2811428159 return result;
2811528160 }
2811628161
28117- function getCandidateDiscriminantPropertyAccess(expr: Expression) {
28118- if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) {
28119- // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in
28120- // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or
28121- // parameter declared in the same parameter list is a candidate.
28122- if (isIdentifier(expr)) {
28123- const symbol = getResolvedSymbol(expr);
28124- const declaration = symbol.valueDeclaration;
28125- if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) {
28126- return declaration;
28127- }
28128- }
28129- }
28130- else if (isAccessExpression(expr)) {
28131- // An access expression is a candidate if the reference matches the left hand expression.
28132- if (isMatchingReference(reference, expr.expression)) {
28133- return expr;
28134- }
28135- }
28136- else if (isIdentifier(expr)) {
28137- const symbol = getResolvedSymbol(expr);
28138- if (isConstantVariable(symbol)) {
28139- const declaration = symbol.valueDeclaration!;
28140- // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind'
28141- if (
28142- isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) &&
28143- isMatchingReference(reference, declaration.initializer.expression)
28144- ) {
28145- return declaration.initializer;
28146- }
28147- // Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind'
28148- if (isBindingElement(declaration) && !declaration.initializer) {
28149- const parent = declaration.parent.parent;
28150- if (
28151- isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) &&
28152- isMatchingReference(reference, parent.initializer)
28153- ) {
28154- return declaration;
28155- }
28156- }
28157- }
28158- }
28159- return undefined;
28160- }
28161-
2816228162 function getDiscriminantPropertyAccess(expr: Expression, computedType: Type) {
2816328163 // As long as the computed type is a subset of the declared type, we use the full declared type to detect
2816428164 // a discriminant property. In cases where the computed type isn't a subset, e.g because of a preceding type
2816528165 // predicate narrowing, we use the actual computed type.
2816628166 if (declaredType.flags & TypeFlags.Union || computedType.flags & TypeFlags.Union) {
28167- const access = getCandidateDiscriminantPropertyAccess(expr);
28167+ const access = getCandidateDiscriminantPropertyAccess(expr, reference );
2816828168 if (access) {
2816928169 const name = getAccessedPropertyName(access);
2817028170 if (name) {
0 commit comments