diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a5c161abae051..38edca0dcbca5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29247,26 +29247,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getResolvedSymbol(expr); if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration!; + let initializer = getCandidateVariableDeclarationInitializer(declaration); // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind' - if ( - isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) && - isMatchingReference(reference, declaration.initializer.expression) - ) { - return declaration.initializer; + if (initializer && isAccessExpression(initializer) && isMatchingReference(reference, initializer.expression)) { + return initializer; } // Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind' if (isBindingElement(declaration) && !declaration.initializer) { - const parent = declaration.parent.parent; - if ( - isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) && - isMatchingReference(reference, parent.initializer) - ) { + initializer = getCandidateVariableDeclarationInitializer(declaration.parent.parent); + if (initializer && (isIdentifier(initializer) || isAccessExpression(initializer)) && isMatchingReference(reference, initializer)) { return declaration; } } } } return undefined; + + function getCandidateVariableDeclarationInitializer(node: Node) { + return isVariableDeclaration(node) && !node.type && node.initializer ? skipParentheses(node.initializer) : undefined; + } } function getDiscriminantPropertyAccess(expr: Expression, computedType: Type) { diff --git a/tests/baselines/reference/controlFlowAliasing2.symbols b/tests/baselines/reference/controlFlowAliasing2.symbols new file mode 100644 index 0000000000000..4084724e242a2 --- /dev/null +++ b/tests/baselines/reference/controlFlowAliasing2.symbols @@ -0,0 +1,292 @@ +//// [tests/cases/conformance/controlFlow/controlFlowAliasing2.ts] //// + +=== controlFlowAliasing2.ts === +// https://github.com/microsoft/TypeScript/issues/61784 + +type Test = TestA | TestB; +>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0)) +>TestA : Symbol(TestA, Decl(controlFlowAliasing2.ts, 2, 26)) +>TestB : Symbol(TestB, Decl(controlFlowAliasing2.ts, 7, 1)) + +interface TestA { +>TestA : Symbol(TestA, Decl(controlFlowAliasing2.ts, 2, 26)) + + type: 'a'; +>type : Symbol(TestA.type, Decl(controlFlowAliasing2.ts, 4, 17)) + + name: string; +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +} + +interface TestB { +>TestB : Symbol(TestB, Decl(controlFlowAliasing2.ts, 7, 1)) + + type: 'b'; +>type : Symbol(TestB.type, Decl(controlFlowAliasing2.ts, 9, 17)) + + value: number; +>value : Symbol(TestB.value, Decl(controlFlowAliasing2.ts, 10, 12)) +} + +function _tcb1(this: { test: Test }) { +>_tcb1 : Symbol(_tcb1, Decl(controlFlowAliasing2.ts, 12, 1)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0)) + + // TS generated by Angular's Type Check block + const _t1 = (((((this).test)).type)); +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 16, 7)) +>(((this).test)).type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) + + if (_t1 === "a") { +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 16, 7)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above, without the parenthesis + const _t2 = this.test.type; +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 22, 7)) +>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) + + if (_t2 === "a") { +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 22, 7)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above without parenthesis at both places + const testType = this.test.type; +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 28, 7)) +>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) + + if (testType === "a") { +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 28, 7)) + + this.test.name; +>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } +} + +function _tcb2(this: { test: Test }) { +>_tcb2 : Symbol(_tcb2, Decl(controlFlowAliasing2.ts, 32, 1)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0)) + + // TS generated by Angular's Type Check block + const _t1 = (((((this).test)).type)); +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 36, 7)) +>(((this).test)).type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) + + if ("a" === _t1) { +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 36, 7)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above, without the parenthesis + const _t2 = this.test.type; +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 42, 7)) +>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) + + if ("a" === _t2) { +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 42, 7)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above without parenthesis at both places + const testType = this.test.type; +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 48, 7)) +>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) + + if ("a" === testType) { +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 48, 7)) + + this.test.name; +>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } +} + +function _tcb3(this: { test: Test }) { +>_tcb3 : Symbol(_tcb3, Decl(controlFlowAliasing2.ts, 52, 1)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0)) + + const { type: _t1 } = (((((this).test)))); +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 55, 9)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) + + if (_t1 === "a") { +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 55, 9)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above, without the parenthesis + const { type: _t2 } = this.test; +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 61, 9)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) + + if (_t2 === "a") { +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 61, 9)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above without parenthesis at both places + const { type: testType } = this.test; +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 67, 9)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) + + if (testType === "a") { +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 67, 9)) + + this.test.name; +>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } +} + +function _tcb4(this: { test: Test }) { +>_tcb4 : Symbol(_tcb4, Decl(controlFlowAliasing2.ts, 71, 1)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0)) + + const { type: _t1 } = (((((this).test)))); +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 74, 9)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) + + if ("a" === _t1) { +>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 74, 9)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above, without the parenthesis + const { type: _t2 } = this.test; +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 80, 9)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) + + if ("a" === _t2) { +>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 80, 9)) + + (((((this).test)).name)); +>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } + + // Same as above without parenthesis at both places + const { type: testType } = this.test; +>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17)) +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 86, 9)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) + + if ("a" === testType) { +>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 86, 9)) + + this.test.name; +>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) +>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15)) +>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22)) +>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12)) + } +} + +export {}; + diff --git a/tests/baselines/reference/controlFlowAliasing2.types b/tests/baselines/reference/controlFlowAliasing2.types new file mode 100644 index 0000000000000..d8e33281cd4f8 --- /dev/null +++ b/tests/baselines/reference/controlFlowAliasing2.types @@ -0,0 +1,605 @@ +//// [tests/cases/conformance/controlFlow/controlFlowAliasing2.ts] //// + +=== controlFlowAliasing2.ts === +// https://github.com/microsoft/TypeScript/issues/61784 + +type Test = TestA | TestB; +>Test : Test +> : ^^^^ + +interface TestA { + type: 'a'; +>type : "a" +> : ^^^ + + name: string; +>name : string +> : ^^^^^^ +} + +interface TestB { + type: 'b'; +>type : "b" +> : ^^^ + + value: number; +>value : number +> : ^^^^^^ +} + +function _tcb1(this: { test: Test }) { +>_tcb1 : (this: { test: Test; }) => void +> : ^ ^^ ^^^^^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + // TS generated by Angular's Type Check block + const _t1 = (((((this).test)).type)); +>_t1 : "a" | "b" +> : ^^^^^^^^^ +>(((((this).test)).type)) : "a" | "b" +> : ^^^^^^^^^ +>((((this).test)).type) : "a" | "b" +> : ^^^^^^^^^ +>(((this).test)).type : "a" | "b" +> : ^^^^^^^^^ +>(((this).test)) : Test +> : ^^^^ +>((this).test) : Test +> : ^^^^ +>(this).test : Test +> : ^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ +>type : "a" | "b" +> : ^^^^^^^^^ + + if (_t1 === "a") { +>_t1 === "a" : boolean +> : ^^^^^^^ +>_t1 : "a" | "b" +> : ^^^^^^^^^ +>"a" : "a" +> : ^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above, without the parenthesis + const _t2 = this.test.type; +>_t2 : "a" | "b" +> : ^^^^^^^^^ +>this.test.type : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ +>type : "a" | "b" +> : ^^^^^^^^^ + + if (_t2 === "a") { +>_t2 === "a" : boolean +> : ^^^^^^^ +>_t2 : "a" | "b" +> : ^^^^^^^^^ +>"a" : "a" +> : ^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above without parenthesis at both places + const testType = this.test.type; +>testType : "a" | "b" +> : ^^^^^^^^^ +>this.test.type : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ +>type : "a" | "b" +> : ^^^^^^^^^ + + if (testType === "a") { +>testType === "a" : boolean +> : ^^^^^^^ +>testType : "a" | "b" +> : ^^^^^^^^^ +>"a" : "a" +> : ^^^ + + this.test.name; +>this.test.name : string +> : ^^^^^^ +>this.test : TestA +> : ^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } +} + +function _tcb2(this: { test: Test }) { +>_tcb2 : (this: { test: Test; }) => void +> : ^ ^^ ^^^^^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + // TS generated by Angular's Type Check block + const _t1 = (((((this).test)).type)); +>_t1 : "a" | "b" +> : ^^^^^^^^^ +>(((((this).test)).type)) : "a" | "b" +> : ^^^^^^^^^ +>((((this).test)).type) : "a" | "b" +> : ^^^^^^^^^ +>(((this).test)).type : "a" | "b" +> : ^^^^^^^^^ +>(((this).test)) : Test +> : ^^^^ +>((this).test) : Test +> : ^^^^ +>(this).test : Test +> : ^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ +>type : "a" | "b" +> : ^^^^^^^^^ + + if ("a" === _t1) { +>"a" === _t1 : boolean +> : ^^^^^^^ +>"a" : "a" +> : ^^^ +>_t1 : "a" | "b" +> : ^^^^^^^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above, without the parenthesis + const _t2 = this.test.type; +>_t2 : "a" | "b" +> : ^^^^^^^^^ +>this.test.type : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ +>type : "a" | "b" +> : ^^^^^^^^^ + + if ("a" === _t2) { +>"a" === _t2 : boolean +> : ^^^^^^^ +>"a" : "a" +> : ^^^ +>_t2 : "a" | "b" +> : ^^^^^^^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above without parenthesis at both places + const testType = this.test.type; +>testType : "a" | "b" +> : ^^^^^^^^^ +>this.test.type : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ +>type : "a" | "b" +> : ^^^^^^^^^ + + if ("a" === testType) { +>"a" === testType : boolean +> : ^^^^^^^ +>"a" : "a" +> : ^^^ +>testType : "a" | "b" +> : ^^^^^^^^^ + + this.test.name; +>this.test.name : string +> : ^^^^^^ +>this.test : TestA +> : ^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } +} + +function _tcb3(this: { test: Test }) { +>_tcb3 : (this: { test: Test; }) => void +> : ^ ^^ ^^^^^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + const { type: _t1 } = (((((this).test)))); +>type : any +> : ^^^ +>_t1 : "a" | "b" +> : ^^^^^^^^^ +>(((((this).test)))) : Test +> : ^^^^ +>((((this).test))) : Test +> : ^^^^ +>(((this).test)) : Test +> : ^^^^ +>((this).test) : Test +> : ^^^^ +>(this).test : Test +> : ^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + if (_t1 === "a") { +>_t1 === "a" : boolean +> : ^^^^^^^ +>_t1 : "a" | "b" +> : ^^^^^^^^^ +>"a" : "a" +> : ^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above, without the parenthesis + const { type: _t2 } = this.test; +>type : any +> : ^^^ +>_t2 : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + if (_t2 === "a") { +>_t2 === "a" : boolean +> : ^^^^^^^ +>_t2 : "a" | "b" +> : ^^^^^^^^^ +>"a" : "a" +> : ^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above without parenthesis at both places + const { type: testType } = this.test; +>type : any +> : ^^^ +>testType : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + if (testType === "a") { +>testType === "a" : boolean +> : ^^^^^^^ +>testType : "a" | "b" +> : ^^^^^^^^^ +>"a" : "a" +> : ^^^ + + this.test.name; +>this.test.name : string +> : ^^^^^^ +>this.test : TestA +> : ^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } +} + +function _tcb4(this: { test: Test }) { +>_tcb4 : (this: { test: Test; }) => void +> : ^ ^^ ^^^^^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + const { type: _t1 } = (((((this).test)))); +>type : any +> : ^^^ +>_t1 : "a" | "b" +> : ^^^^^^^^^ +>(((((this).test)))) : Test +> : ^^^^ +>((((this).test))) : Test +> : ^^^^ +>(((this).test)) : Test +> : ^^^^ +>((this).test) : Test +> : ^^^^ +>(this).test : Test +> : ^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + if ("a" === _t1) { +>"a" === _t1 : boolean +> : ^^^^^^^ +>"a" : "a" +> : ^^^ +>_t1 : "a" | "b" +> : ^^^^^^^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above, without the parenthesis + const { type: _t2 } = this.test; +>type : any +> : ^^^ +>_t2 : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + if ("a" === _t2) { +>"a" === _t2 : boolean +> : ^^^^^^^ +>"a" : "a" +> : ^^^ +>_t2 : "a" | "b" +> : ^^^^^^^^^ + + (((((this).test)).name)); +>(((((this).test)).name)) : string +> : ^^^^^^ +>((((this).test)).name) : string +> : ^^^^^^ +>(((this).test)).name : string +> : ^^^^^^ +>(((this).test)) : TestA +> : ^^^^^ +>((this).test) : TestA +> : ^^^^^ +>(this).test : TestA +> : ^^^^^ +>(this) : { test: Test; } +> : ^^^^^^^^ ^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } + + // Same as above without parenthesis at both places + const { type: testType } = this.test; +>type : any +> : ^^^ +>testType : "a" | "b" +> : ^^^^^^^^^ +>this.test : Test +> : ^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : Test +> : ^^^^ + + if ("a" === testType) { +>"a" === testType : boolean +> : ^^^^^^^ +>"a" : "a" +> : ^^^ +>testType : "a" | "b" +> : ^^^^^^^^^ + + this.test.name; +>this.test.name : string +> : ^^^^^^ +>this.test : TestA +> : ^^^^^ +>this : { test: Test; } +> : ^^^^^^^^ ^^^ +>test : TestA +> : ^^^^^ +>name : string +> : ^^^^^^ + } +} + +export {}; + diff --git a/tests/cases/conformance/controlFlow/controlFlowAliasing2.ts b/tests/cases/conformance/controlFlow/controlFlowAliasing2.ts new file mode 100644 index 0000000000000..250e5c5832448 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowAliasing2.ts @@ -0,0 +1,96 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/61784 + +type Test = TestA | TestB; + +interface TestA { + type: 'a'; + name: string; +} + +interface TestB { + type: 'b'; + value: number; +} + +function _tcb1(this: { test: Test }) { + // TS generated by Angular's Type Check block + const _t1 = (((((this).test)).type)); + if (_t1 === "a") { + (((((this).test)).name)); + } + + // Same as above, without the parenthesis + const _t2 = this.test.type; + if (_t2 === "a") { + (((((this).test)).name)); + } + + // Same as above without parenthesis at both places + const testType = this.test.type; + if (testType === "a") { + this.test.name; + } +} + +function _tcb2(this: { test: Test }) { + // TS generated by Angular's Type Check block + const _t1 = (((((this).test)).type)); + if ("a" === _t1) { + (((((this).test)).name)); + } + + // Same as above, without the parenthesis + const _t2 = this.test.type; + if ("a" === _t2) { + (((((this).test)).name)); + } + + // Same as above without parenthesis at both places + const testType = this.test.type; + if ("a" === testType) { + this.test.name; + } +} + +function _tcb3(this: { test: Test }) { + const { type: _t1 } = (((((this).test)))); + if (_t1 === "a") { + (((((this).test)).name)); + } + + // Same as above, without the parenthesis + const { type: _t2 } = this.test; + if (_t2 === "a") { + (((((this).test)).name)); + } + + // Same as above without parenthesis at both places + const { type: testType } = this.test; + if (testType === "a") { + this.test.name; + } +} + +function _tcb4(this: { test: Test }) { + const { type: _t1 } = (((((this).test)))); + if ("a" === _t1) { + (((((this).test)).name)); + } + + // Same as above, without the parenthesis + const { type: _t2 } = this.test; + if ("a" === _t2) { + (((((this).test)).name)); + } + + // Same as above without parenthesis at both places + const { type: testType } = this.test; + if ("a" === testType) { + this.test.name; + } +} + +export {};