diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9ea90805fb51e..5980b113e7baf 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3869,6 +3869,9 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.ModuleBlock: return ContainerFlags.IsControlFlowContainer; + case SyntaxKind.PropertyDeclaration: + return (node as PropertyDeclaration).initializer ? ContainerFlags.IsControlFlowContainer : ContainerFlags.None; + case SyntaxKind.CatchClause: case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: diff --git a/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.js b/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.js new file mode 100644 index 0000000000000..3293aa9e34a7b --- /dev/null +++ b/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.js @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.ts] //// + +//// [classPropertyInferenceFromBroaderTypeConst.ts] +// Repro from GH#62264 +// Class property should infer the wider declared type (AB), not the narrowed literal type ("A") + +type AB = 'A' | 'B'; + +const DEFAULT: AB = 'A'; + +class C { + D = DEFAULT; + + method() { + switch (this.D) { + case 'A': break; + case 'B': break; // should not error + } + } +} + +// D should be AB, not "A" +declare const c: C; +declare function expectAB(x: AB): void; +expectAB(c.D); // ok +c.D = 'B'; // ok + +// Static property should work the same way +class D { + static SD = DEFAULT; +} +D.SD = 'B'; // ok + + +//// [classPropertyInferenceFromBroaderTypeConst.js] +"use strict"; +// Repro from GH#62264 +// Class property should infer the wider declared type (AB), not the narrowed literal type ("A") +const DEFAULT = 'A'; +class C { + D = DEFAULT; + method() { + switch (this.D) { + case 'A': break; + case 'B': break; // should not error + } + } +} +expectAB(c.D); // ok +c.D = 'B'; // ok +// Static property should work the same way +class D { + static SD = DEFAULT; +} +D.SD = 'B'; // ok diff --git a/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.symbols b/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.symbols new file mode 100644 index 0000000000000..997b69e5225b0 --- /dev/null +++ b/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.symbols @@ -0,0 +1,68 @@ +//// [tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.ts] //// + +=== classPropertyInferenceFromBroaderTypeConst.ts === +// Repro from GH#62264 +// Class property should infer the wider declared type (AB), not the narrowed literal type ("A") + +type AB = 'A' | 'B'; +>AB : Symbol(AB, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 0, 0)) + +const DEFAULT: AB = 'A'; +>DEFAULT : Symbol(DEFAULT, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 5, 5)) +>AB : Symbol(AB, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 0, 0)) + +class C { +>C : Symbol(C, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 5, 24)) + + D = DEFAULT; +>D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) +>DEFAULT : Symbol(DEFAULT, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 5, 5)) + + method() { +>method : Symbol(C.method, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 8, 16)) + + switch (this.D) { +>this.D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) +>this : Symbol(C, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 5, 24)) +>D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) + + case 'A': break; + case 'B': break; // should not error + } + } +} + +// D should be AB, not "A" +declare const c: C; +>c : Symbol(c, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 19, 13)) +>C : Symbol(C, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 5, 24)) + +declare function expectAB(x: AB): void; +>expectAB : Symbol(expectAB, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 19, 19)) +>x : Symbol(x, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 20, 26)) +>AB : Symbol(AB, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 0, 0)) + +expectAB(c.D); // ok +>expectAB : Symbol(expectAB, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 19, 19)) +>c.D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) +>c : Symbol(c, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 19, 13)) +>D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) + +c.D = 'B'; // ok +>c.D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) +>c : Symbol(c, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 19, 13)) +>D : Symbol(C.D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 7, 9)) + +// Static property should work the same way +class D { +>D : Symbol(D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 22, 10)) + + static SD = DEFAULT; +>SD : Symbol(D.SD, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 25, 9)) +>DEFAULT : Symbol(DEFAULT, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 5, 5)) +} +D.SD = 'B'; // ok +>D.SD : Symbol(D.SD, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 25, 9)) +>D : Symbol(D, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 22, 10)) +>SD : Symbol(D.SD, Decl(classPropertyInferenceFromBroaderTypeConst.ts, 25, 9)) + diff --git a/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.types b/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.types new file mode 100644 index 0000000000000..e339f502bae82 --- /dev/null +++ b/tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.types @@ -0,0 +1,107 @@ +//// [tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.ts] //// + +=== classPropertyInferenceFromBroaderTypeConst.ts === +// Repro from GH#62264 +// Class property should infer the wider declared type (AB), not the narrowed literal type ("A") + +type AB = 'A' | 'B'; +>AB : AB +> : ^^ + +const DEFAULT: AB = 'A'; +>DEFAULT : AB +> : ^^ +>'A' : "A" +> : ^^^ + +class C { +>C : C +> : ^ + + D = DEFAULT; +>D : AB +> : ^^ +>DEFAULT : AB +> : ^^ + + method() { +>method : () => void +> : ^^^^^^^^^^ + + switch (this.D) { +>this.D : AB +> : ^^ +>this : this +> : ^^^^ +>D : AB +> : ^^ + + case 'A': break; +>'A' : "A" +> : ^^^ + + case 'B': break; // should not error +>'B' : "B" +> : ^^^ + } + } +} + +// D should be AB, not "A" +declare const c: C; +>c : C +> : ^ + +declare function expectAB(x: AB): void; +>expectAB : (x: AB) => void +> : ^ ^^ ^^^^^ +>x : AB +> : ^^ + +expectAB(c.D); // ok +>expectAB(c.D) : void +> : ^^^^ +>expectAB : (x: AB) => void +> : ^ ^^ ^^^^^ +>c.D : AB +> : ^^ +>c : C +> : ^ +>D : AB +> : ^^ + +c.D = 'B'; // ok +>c.D = 'B' : "B" +> : ^^^ +>c.D : AB +> : ^^ +>c : C +> : ^ +>D : AB +> : ^^ +>'B' : "B" +> : ^^^ + +// Static property should work the same way +class D { +>D : D +> : ^ + + static SD = DEFAULT; +>SD : AB +> : ^^ +>DEFAULT : AB +> : ^^ +} +D.SD = 'B'; // ok +>D.SD = 'B' : "B" +> : ^^^ +>D.SD : AB +> : ^^ +>D : typeof D +> : ^^^^^^^^ +>SD : AB +> : ^^ +>'B' : "B" +> : ^^^ + diff --git a/tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.ts b/tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.ts new file mode 100644 index 0000000000000..33faa717d76d6 --- /dev/null +++ b/tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.ts @@ -0,0 +1,31 @@ +// @strict: true + +// Repro from GH#62264 +// Class property should infer the wider declared type (AB), not the narrowed literal type ("A") + +type AB = 'A' | 'B'; + +const DEFAULT: AB = 'A'; + +class C { + D = DEFAULT; + + method() { + switch (this.D) { + case 'A': break; + case 'B': break; // should not error + } + } +} + +// D should be AB, not "A" +declare const c: C; +declare function expectAB(x: AB): void; +expectAB(c.D); // ok +c.D = 'B'; // ok + +// Static property should work the same way +class D { + static SD = DEFAULT; +} +D.SD = 'B'; // ok