Skip to content

Commit

Permalink
Allow auto accessor types to be inferred from their flow types in con…
Browse files Browse the repository at this point in the history
…structors and static blocks (#59732)

Co-authored-by: Ron Buckton <[email protected]>
  • Loading branch information
Andarist and rbuckton authored Oct 16, 2024
1 parent 3b0dfaa commit 03c5a37
Show file tree
Hide file tree
Showing 28 changed files with 1,314 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12005,7 +12005,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
getAnnotatedAccessorType(setter) ||
getAnnotatedAccessorType(accessor) ||
getter && getter.body && getReturnTypeFromBody(getter) ||
accessor && accessor.initializer && getWidenedTypeForVariableLikeDeclaration(accessor, /*reportErrors*/ true);
accessor && getWidenedTypeForVariableLikeDeclaration(accessor, /*reportErrors*/ true);
if (!type) {
if (setter && !isPrivateWithinAmbient(setter)) {
errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//// [tests/cases/compiler/classAccessorInitializationInferenceWithElementAccess1.ts] ////

//// [classAccessorInitializationInferenceWithElementAccess1.ts]
export class Cls {
accessor x;
accessor y;
accessor z;

accessor 0;

constructor(seed: number) {
this['x'] = [seed];
this['y'] = { seed };
this['z'] = `${seed}`;

this[0] = [seed];
}
}


//// [classAccessorInitializationInferenceWithElementAccess1.js]
export class Cls {
accessor x;
accessor y;
accessor z;
accessor 0;
constructor(seed) {
this['x'] = [seed];
this['y'] = { seed };
this['z'] = `${seed}`;
this[0] = [seed];
}
}


//// [classAccessorInitializationInferenceWithElementAccess1.d.ts]
export declare class Cls {
accessor x: number[];
accessor y: {
seed: number;
};
accessor z: string;
accessor 0: number[];
constructor(seed: number);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//// [tests/cases/compiler/classAccessorInitializationInferenceWithElementAccess1.ts] ////

=== classAccessorInitializationInferenceWithElementAccess1.ts ===
export class Cls {
>Cls : Symbol(Cls, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 0))

accessor x;
>x : Symbol(Cls.x, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 18))

accessor y;
>y : Symbol(Cls.y, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 1, 15))

accessor z;
>z : Symbol(Cls.z, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 2, 15))

accessor 0;
>0 : Symbol(Cls[0], Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 3, 15))

constructor(seed: number) {
>seed : Symbol(seed, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 7, 16))

this['x'] = [seed];
>this : Symbol(Cls, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 0))
>'x' : Symbol(Cls.x, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 18))
>seed : Symbol(seed, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 7, 16))

this['y'] = { seed };
>this : Symbol(Cls, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 0))
>'y' : Symbol(Cls.y, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 1, 15))
>seed : Symbol(seed, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 9, 21))

this['z'] = `${seed}`;
>this : Symbol(Cls, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 0))
>'z' : Symbol(Cls.z, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 2, 15))
>seed : Symbol(seed, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 7, 16))

this[0] = [seed];
>this : Symbol(Cls, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 0, 0))
>0 : Symbol(Cls[0], Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 3, 15))
>seed : Symbol(seed, Decl(classAccessorInitializationInferenceWithElementAccess1.ts, 7, 16))
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//// [tests/cases/compiler/classAccessorInitializationInferenceWithElementAccess1.ts] ////

=== classAccessorInitializationInferenceWithElementAccess1.ts ===
export class Cls {
>Cls : Cls
> : ^^^

accessor x;
>x : number[]
> : ^^^^^^^^

accessor y;
>y : { seed: number; }
> : ^^^^^^^^^^^^^^^^^

accessor z;
>z : string
> : ^^^^^^

accessor 0;
>0 : number[]
> : ^^^^^^^^

constructor(seed: number) {
>seed : number
> : ^^^^^^

this['x'] = [seed];
>this['x'] = [seed] : number[]
> : ^^^^^^^^
>this['x'] : number[]
> : ^^^^^^^^
>this : this
> : ^^^^
>'x' : "x"
> : ^^^
>[seed] : number[]
> : ^^^^^^^^
>seed : number
> : ^^^^^^

this['y'] = { seed };
>this['y'] = { seed } : { seed: number; }
> : ^^^^^^^^^^^^^^^^^
>this['y'] : { seed: number; }
> : ^^^^^^^^^^^^^^^^^
>this : this
> : ^^^^
>'y' : "y"
> : ^^^
>{ seed } : { seed: number; }
> : ^^^^^^^^^^^^^^^^^
>seed : number
> : ^^^^^^

this['z'] = `${seed}`;
>this['z'] = `${seed}` : string
> : ^^^^^^
>this['z'] : string
> : ^^^^^^
>this : this
> : ^^^^
>'z' : "z"
> : ^^^
>`${seed}` : string
> : ^^^^^^
>seed : number
> : ^^^^^^

this[0] = [seed];
>this[0] = [seed] : number[]
> : ^^^^^^^^
>this[0] : number[]
> : ^^^^^^^^
>this : this
> : ^^^^
>0 : 0
> : ^
>[seed] : number[]
> : ^^^^^^^^
>seed : number
> : ^^^^^^
}
}

44 changes: 35 additions & 9 deletions tests/baselines/reference/classAttributeInferenceTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,42 @@ class MyClass {

const localProperty = `foo-${variable}`; // Correctly inferred as `string`
}
}
}

class MyClass2 {
accessor property;
accessor property2;

constructor() {
const variable = 'something'

this.property = `foo`; // Correctly inferred as `string`
this.property2 = `foo-${variable}`; // Causes an error

const localProperty = `foo-${variable}`; // Correctly inferred as `string`
}
}


//// [classAttributeInferenceTemplate.js]
"use strict";
var MyClass = /** @class */ (function () {
function MyClass() {
var variable = 'something';
this.property = "foo"; // Correctly inferred as `string`
this.property2 = "foo-".concat(variable); // Causes an error
var localProperty = "foo-".concat(variable); // Correctly inferred as `string`
class MyClass {
property;
property2;
constructor() {
const variable = 'something';
this.property = `foo`; // Correctly inferred as `string`
this.property2 = `foo-${variable}`; // Causes an error
const localProperty = `foo-${variable}`; // Correctly inferred as `string`
}
return MyClass;
}());
}
class MyClass2 {
accessor property;
accessor property2;
constructor() {
const variable = 'something';
this.property = `foo`; // Correctly inferred as `string`
this.property2 = `foo-${variable}`; // Causes an error
const localProperty = `foo-${variable}`; // Correctly inferred as `string`
}
}
31 changes: 31 additions & 0 deletions tests/baselines/reference/classAttributeInferenceTemplate.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,34 @@ class MyClass {
>variable : Symbol(variable, Decl(classAttributeInferenceTemplate.ts, 5, 13))
}
}

class MyClass2 {
>MyClass2 : Symbol(MyClass2, Decl(classAttributeInferenceTemplate.ts, 12, 1))

accessor property;
>property : Symbol(MyClass2.property, Decl(classAttributeInferenceTemplate.ts, 14, 16))

accessor property2;
>property2 : Symbol(MyClass2.property2, Decl(classAttributeInferenceTemplate.ts, 15, 22))

constructor() {
const variable = 'something'
>variable : Symbol(variable, Decl(classAttributeInferenceTemplate.ts, 19, 13))

this.property = `foo`; // Correctly inferred as `string`
>this.property : Symbol(MyClass2.property, Decl(classAttributeInferenceTemplate.ts, 14, 16))
>this : Symbol(MyClass2, Decl(classAttributeInferenceTemplate.ts, 12, 1))
>property : Symbol(MyClass2.property, Decl(classAttributeInferenceTemplate.ts, 14, 16))

this.property2 = `foo-${variable}`; // Causes an error
>this.property2 : Symbol(MyClass2.property2, Decl(classAttributeInferenceTemplate.ts, 15, 22))
>this : Symbol(MyClass2, Decl(classAttributeInferenceTemplate.ts, 12, 1))
>property2 : Symbol(MyClass2.property2, Decl(classAttributeInferenceTemplate.ts, 15, 22))
>variable : Symbol(variable, Decl(classAttributeInferenceTemplate.ts, 19, 13))

const localProperty = `foo-${variable}`; // Correctly inferred as `string`
>localProperty : Symbol(localProperty, Decl(classAttributeInferenceTemplate.ts, 24, 13))
>variable : Symbol(variable, Decl(classAttributeInferenceTemplate.ts, 19, 13))
}
}

56 changes: 56 additions & 0 deletions tests/baselines/reference/classAttributeInferenceTemplate.types
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,59 @@ class MyClass {
> : ^^^^^^^^^^^
}
}

class MyClass2 {
>MyClass2 : MyClass2
> : ^^^^^^^^

accessor property;
>property : string
> : ^^^^^^

accessor property2;
>property2 : string
> : ^^^^^^

constructor() {
const variable = 'something'
>variable : "something"
> : ^^^^^^^^^^^
>'something' : "something"
> : ^^^^^^^^^^^

this.property = `foo`; // Correctly inferred as `string`
>this.property = `foo` : "foo"
> : ^^^^^
>this.property : string
> : ^^^^^^
>this : this
> : ^^^^
>property : string
> : ^^^^^^
>`foo` : "foo"
> : ^^^^^

this.property2 = `foo-${variable}`; // Causes an error
>this.property2 = `foo-${variable}` : "foo-something"
> : ^^^^^^^^^^^^^^^
>this.property2 : string
> : ^^^^^^
>this : this
> : ^^^^
>property2 : string
> : ^^^^^^
>`foo-${variable}` : "foo-something"
> : ^^^^^^^^^^^^^^^
>variable : "something"
> : ^^^^^^^^^^^

const localProperty = `foo-${variable}`; // Correctly inferred as `string`
>localProperty : "foo-something"
> : ^^^^^^^^^^^^^^^
>`foo-${variable}` : "foo-something"
> : ^^^^^^^^^^^^^^^
>variable : "something"
> : ^^^^^^^^^^^
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,34 @@ class MyClass {
>variable : Symbol(variable, Decl(index.js, 5, 13))
}
}

class MyClass2 {
>MyClass2 : Symbol(MyClass2, Decl(index.js, 12, 1))

accessor property;
>property : Symbol(MyClass2.property, Decl(index.js, 14, 16))

accessor property2;
>property2 : Symbol(MyClass2.property2, Decl(index.js, 15, 22))

constructor() {
const variable = 'something'
>variable : Symbol(variable, Decl(index.js, 19, 13))

this.property = `foo`; // Correctly inferred as `string`
>this.property : Symbol(MyClass2.property, Decl(index.js, 14, 16))
>this : Symbol(MyClass2, Decl(index.js, 12, 1))
>property : Symbol(MyClass2.property, Decl(index.js, 14, 16))

this.property2 = `foo-${variable}`; // Causes an error
>this.property2 : Symbol(MyClass2.property2, Decl(index.js, 15, 22))
>this : Symbol(MyClass2, Decl(index.js, 12, 1))
>property2 : Symbol(MyClass2.property2, Decl(index.js, 15, 22))
>variable : Symbol(variable, Decl(index.js, 19, 13))

const localProperty = `foo-${variable}`; // Correctly inferred as `string`
>localProperty : Symbol(localProperty, Decl(index.js, 24, 13))
>variable : Symbol(variable, Decl(index.js, 19, 13))
}
}

Loading

0 comments on commit 03c5a37

Please sign in to comment.