Skip to content

Commit 3919042

Browse files
authored
Control flow for constructor initialized properties (microsoft#37920)
* Use CFA to determine types of properties declared by this.xxx assignments * Accept new baselines * Also use CFA in constructor functions * Accept new baselines * Fix lint error * Only widen fresh literal types in CFA of assignment to auto-typed * Auto-typing for declared properties with no type annotation or initializer * Add optionality if declaration includes '?' modifier * Always use CFA for properties with no initializer in .js files * Small fix
1 parent a0ebd2c commit 3919042

File tree

63 files changed

+327
-248
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+327
-248
lines changed

src/compiler/binder.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ namespace ts {
649649
}
650650
// We create a return control flow graph for IIFEs and constructors. For constructors
651651
// we use the return control flow graph in strict property initialization checks.
652-
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor ? createBranchLabel() : undefined;
652+
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || (isInJSFile && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
653653
currentExceptionTarget = undefined;
654654
currentBreakTarget = undefined;
655655
currentContinueTarget = undefined;
@@ -670,8 +670,8 @@ namespace ts {
670670
if (currentReturnTarget) {
671671
addAntecedent(currentReturnTarget, currentFlow);
672672
currentFlow = finishFlowLabel(currentReturnTarget);
673-
if (node.kind === SyntaxKind.Constructor) {
674-
(<ConstructorDeclaration>node).returnFlowNode = currentFlow;
673+
if (node.kind === SyntaxKind.Constructor || (isInJSFile && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
674+
(<FunctionLikeDeclaration>node).returnFlowNode = currentFlow;
675675
}
676676
}
677677
if (!isIIFE) {

src/compiler/checker.ts

+129-56
Large diffs are not rendered by default.

src/compiler/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,7 @@ namespace ts {
11071107
exclamationToken?: ExclamationToken;
11081108
body?: Block | Expression;
11091109
/* @internal */ endFlowNode?: FlowNode;
1110+
/* @internal */ returnFlowNode?: FlowNode;
11101111
}
11111112

11121113
export type FunctionLikeDeclaration =
@@ -1152,7 +1153,6 @@ namespace ts {
11521153
kind: SyntaxKind.Constructor;
11531154
parent: ClassLikeDeclaration;
11541155
body?: FunctionBody;
1155-
/* @internal */ returnFlowNode?: FlowNode;
11561156
}
11571157

11581158
/** For when we encounter a semicolon in a class declaration. ES6 allows these as class elements. */
@@ -4157,6 +4157,7 @@ namespace ts {
41574157
deferralParent?: Type; // Source union/intersection of a deferred type
41584158
cjsExportMerged?: Symbol; // Version of the symbol with all non export= exports merged with the export= target
41594159
typeOnlyDeclaration?: TypeOnlyCompatibleAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs
4160+
isConstructorDeclaredProperty?: boolean; // Property declared through 'this.x = ...' assignment in constructor
41604161
}
41614162

41624163
/* @internal */

tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ function Person(name) {
105105

106106
this.name = name;
107107
>this.name = name : string
108-
>this.name : string
108+
>this.name : any
109109
>this : this
110-
>name : string
110+
>name : any
111111
>name : string
112112
}
113113
Person.prototype.describe = function () {

tests/baselines/reference/checkIndexConstraintOfJavascriptClassExpression.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ someFunction(function(BaseClass) {
2323

2424
this.foo = "bar";
2525
>this.foo = "bar" : "bar"
26-
>this.foo : string
26+
>this.foo : any
2727
>this : this
28-
>foo : string
28+
>foo : any
2929
>"bar" : "bar"
3030
}
3131
_render(error) {

tests/baselines/reference/checkJsFiles_noErrorLocation.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class B extends A {
2525

2626
this.foo = () => 3;
2727
>this.foo = () => 3 : () => number
28-
>this.foo : () => number
28+
>this.foo : any
2929
>this : this
30-
>foo : () => number
30+
>foo : any
3131
>() => 3 : () => number
3232
>3 : 3
3333
}

tests/baselines/reference/checkSuperCallBeforeThisAccessing9.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ class Derived {
1212

1313
this.x = 10;
1414
>this.x = 10 : 10
15-
>this.x : number
15+
>this.x : any
1616
>this : this
17-
>x : number
17+
>x : any
1818
>10 : 10
1919

2020
var that = this;

tests/baselines/reference/classCanExtendConstructorFunction.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ function Wagon(numberOxen) {
99

1010
this.numberOxen = numberOxen
1111
>this.numberOxen = numberOxen : number
12-
>this.numberOxen : number
12+
>this.numberOxen : any
1313
>this : this
14-
>numberOxen : number
14+
>numberOxen : any
1515
>numberOxen : number
1616
}
1717
/** @param {Wagon[]=} wagons */
@@ -91,9 +91,9 @@ class Sql extends Wagon {
9191

9292
this.foonly = 12
9393
>this.foonly = 12 : 12
94-
>this.foonly : number
94+
>this.foonly : any
9595
>this : this
96-
>foonly : number
96+
>foonly : any
9797
>12 : 12
9898
}
9999
/**

tests/baselines/reference/classExtendingAny.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ class B extends Err {
6767

6868
this.wat = 12
6969
>this.wat = 12 : 12
70-
>this.wat : number
70+
>this.wat : any
7171
>this : this
72-
>wat : number
72+
>wat : any
7373
>12 : 12
7474
}
7575
f() {

tests/baselines/reference/constructorFunctions.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ function C6() {
143143

144144
this.functions = [x => x, x => x + 1, x => x - 1]
145145
>this.functions = [x => x, x => x + 1, x => x - 1] : ((x: any) => any)[]
146-
>this.functions : ((x: any) => any)[]
146+
>this.functions : any
147147
>this : this
148-
>functions : ((x: any) => any)[]
148+
>functions : any
149149
>[x => x, x => x + 1, x => x - 1] : ((x: any) => any)[]
150150
>x => x : (x: any) => any
151151
>x : any

tests/baselines/reference/constructorFunctionsStrict.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ var j = new A(2)
8585

8686
k.x === j.x
8787
>k.x === j.x : boolean
88-
>k.x : number
88+
>k.x : number | undefined
8989
>k : A
90-
>x : number
91-
>j.x : number
90+
>x : number | undefined
91+
>j.x : number | undefined
9292
>j : A
93-
>x : number
93+
>x : number | undefined
9494

tests/baselines/reference/exportNestedNamespaces.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ exports.Classic = class {
3232
constructor() {
3333
this.p = 1
3434
>this.p = 1 : 1
35-
>this.p : number
35+
>this.p : any
3636
>this : this
37-
>p : number
37+
>p : any
3838
>1 : 1
3939
}
4040
}

tests/baselines/reference/inferringClassMembersFromAssignments.types

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,24 @@ class C {
1111

1212
this.inConstructor = 0;
1313
>this.inConstructor = 0 : 0
14-
>this.inConstructor : string | number
14+
>this.inConstructor : any
1515
>this : this
16-
>inConstructor : string | number
16+
>inConstructor : any
1717
>0 : 0
1818
}
1919
else {
2020
this.inConstructor = "string"
2121
>this.inConstructor = "string" : "string"
22-
>this.inConstructor : string | number
22+
>this.inConstructor : any
2323
>this : this
24-
>inConstructor : string | number
24+
>inConstructor : any
2525
>"string" : "string"
2626
}
2727
this.inMultiple = 0;
2828
>this.inMultiple = 0 : 0
29-
>this.inMultiple : number
29+
>this.inMultiple : any
3030
>this : this
31-
>inMultiple : number
31+
>inMultiple : any
3232
>0 : 0
3333
}
3434
method() {

tests/baselines/reference/inferringClassMembersFromAssignments3.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ class Base {
55
constructor() {
66
this.p = 1
77
>this.p = 1 : 1
8-
>this.p : number
8+
>this.p : any
99
>this : this
10-
>p : number
10+
>p : any
1111
>1 : 1
1212
}
1313
}

tests/baselines/reference/inferringClassMembersFromAssignments5.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class Derived extends Base {
2525
// should be OK, and p should have type number from this assignment
2626
this.p = 1
2727
>this.p = 1 : 1
28-
>this.p : number
28+
>this.p : any
2929
>this : this
30-
>p : number
30+
>p : any
3131
>1 : 1
3232
}
3333
test() {

tests/baselines/reference/jsDeclarationsClasses.types

+10-10
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,16 @@ export class K {
209209
constructor() {
210210
this.p1 = 12;
211211
>this.p1 = 12 : 12
212-
>this.p1 : number
212+
>this.p1 : any
213213
>this : this
214-
>p1 : number
214+
>p1 : any
215215
>12 : 12
216216

217217
this.p2 = "ok";
218218
>this.p2 = "ok" : "ok"
219-
>this.p2 : string
219+
>this.p2 : any
220220
>this : this
221-
>p2 : string
221+
>p2 : any
222222
>"ok" : "ok"
223223
}
224224

@@ -243,9 +243,9 @@ export class M extends null {
243243
constructor() {
244244
this.prop = 12;
245245
>this.prop = 12 : 12
246-
>this.prop : number
246+
>this.prop : any
247247
>this : this
248-
>prop : number
248+
>prop : any
249249
>12 : 12
250250
}
251251
}
@@ -270,9 +270,9 @@ export class N extends L {
270270

271271
this.another = param;
272272
>this.another = param : T
273-
>this.another : T
273+
>this.another : any
274274
>this : this
275-
>another : T
275+
>another : any
276276
>param : T
277277
}
278278
}
@@ -298,9 +298,9 @@ export class O extends N {
298298

299299
this.another2 = param;
300300
>this.another2 = param : U
301-
>this.another2 : U
301+
>this.another2 : any
302302
>this : this
303-
>another2 : U
303+
>another2 : any
304304
>param : U
305305
}
306306
}

tests/baselines/reference/jsDeclarationsExportAssignedClassExpression.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ module.exports = class Thing {
1515

1616
this.t = 12 + p;
1717
>this.t = 12 + p : number
18-
>this.t : number
18+
>this.t : any
1919
>this : this
20-
>t : number
20+
>t : any
2121
>12 + p : number
2222
>12 : 12
2323
>p : number

tests/baselines/reference/jsDeclarationsExportAssignedClassExpressionAnonymous.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ module.exports = class {
1414

1515
this.t = 12 + p;
1616
>this.t = 12 + p : number
17-
>this.t : number
17+
>this.t : any
1818
>this : this
19-
>t : number
19+
>t : any
2020
>12 + p : number
2121
>12 : 12
2222
>p : number

tests/baselines/reference/jsDeclarationsExportAssignedClassExpressionAnonymousWithSub.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ module.exports = class {
1414

1515
this.t = 12 + p;
1616
>this.t = 12 + p : number
17-
>this.t : number
17+
>this.t : any
1818
>this : this
19-
>t : number
19+
>t : any
2020
>12 + p : number
2121
>12 : 12
2222
>p : number
@@ -34,9 +34,9 @@ module.exports.Sub = class {
3434
constructor() {
3535
this.instance = new module.exports(10);
3636
>this.instance = new module.exports(10) : import("tests/cases/conformance/jsdoc/declarations/index")
37-
>this.instance : import("tests/cases/conformance/jsdoc/declarations/index")
37+
>this.instance : any
3838
>this : this
39-
>instance : import("tests/cases/conformance/jsdoc/declarations/index")
39+
>instance : any
4040
>new module.exports(10) : import("tests/cases/conformance/jsdoc/declarations/index")
4141
>module.exports : typeof import("tests/cases/conformance/jsdoc/declarations/index")
4242
>module : { "\"tests/cases/conformance/jsdoc/declarations/index\"": typeof import("tests/cases/conformance/jsdoc/declarations/index"); }

tests/baselines/reference/jsDeclarationsExportAssignedClassExpressionShadowing.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ module.exports = class Q {
2525
constructor() {
2626
this.x = new A();
2727
>this.x = new A() : A
28-
>this.x : A
28+
>this.x : any
2929
>this : this
30-
>x : A
30+
>x : any
3131
>new A() : A
3232
>A : typeof A
3333
}

tests/baselines/reference/jsDeclarationsExportAssignedConstructorFunction.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ module.exports.MyClass = function() {
1111

1212
this.x = 1
1313
>this.x = 1 : 1
14-
>this.x : number
14+
>this.x : any
1515
>this : this
16-
>x : number
16+
>x : any
1717
>1 : 1
1818
}
1919
module.exports.MyClass.prototype = {

tests/baselines/reference/jsDeclarationsExportAssignedVisibility.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ class Container {
1111
constructor() {
1212
this.usage = new Obj();
1313
>this.usage = new Obj() : import("tests/cases/conformance/jsdoc/declarations/obj")
14-
>this.usage : import("tests/cases/conformance/jsdoc/declarations/obj")
14+
>this.usage : any
1515
>this : this
16-
>usage : import("tests/cases/conformance/jsdoc/declarations/obj")
16+
>usage : any
1717
>new Obj() : import("tests/cases/conformance/jsdoc/declarations/obj")
1818
>Obj : typeof import("tests/cases/conformance/jsdoc/declarations/obj")
1919
}
@@ -38,9 +38,9 @@ module.exports = class Obj {
3838
constructor() {
3939
this.x = 12;
4040
>this.x = 12 : 12
41-
>this.x : number
41+
>this.x : any
4242
>this : this
43-
>x : number
43+
>x : any
4444
>12 : 12
4545
}
4646
}

tests/baselines/reference/jsDeclarationsTypedefAndImportTypes.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ class Wrap {
3838

3939
this.connItem = c.item;
4040
>this.connItem = c.item : number
41-
>this.connItem : number
41+
>this.connItem : any
4242
>this : this
43-
>connItem : number
43+
>connItem : any
4444
>c.item : number
4545
>c : import("tests/cases/conformance/jsdoc/declarations/conn")
4646
>item : number

tests/baselines/reference/jsFileClassPropertyType.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ class C {
55
constructor () {
66
this.p = 0;
77
>this.p = 0 : 0
8-
>this.p : number
8+
>this.p : any
99
>this : this
10-
>p : number
10+
>p : any
1111
>0 : 0
1212
}
1313
}

0 commit comments

Comments
 (0)