Skip to content

Commit fd9fb8f

Browse files
committed
Support static properties
1 parent 6e86596 commit fd9fb8f

9 files changed

+179
-34
lines changed
Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* @internal */
1+
/* @internal */
22
namespace ts.codefix {
33
registerCodeFix({
44
errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code],
@@ -13,22 +13,27 @@ namespace ts.codefix {
1313
// this.missing = 1;
1414
// ^^^^^^^
1515
const token = getTokenAtPosition(sourceFile, start);
16-
1716
if (token.kind != SyntaxKind.Identifier) {
1817
return undefined;
1918
}
2019

21-
const classDeclaration = getContainingClass(token);
22-
if (!classDeclaration) {
20+
if (!isPropertyAccessExpression(token.parent) || token.parent.expression.kind !== SyntaxKind.ThisKeyword) {
2321
return undefined;
2422
}
2523

26-
if (!isPropertyAccessExpression(token.parent) || token.parent.expression.kind !== SyntaxKind.ThisKeyword) {
24+
const classMemberDeclaration = getThisContainer(token, /*includeArrowFunctions*/ false);
25+
if (!isClassElement(classMemberDeclaration)) {
2726
return undefined;
2827
}
2928

30-
return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile();
29+
const classDeclaration = <ClassLikeDeclaration>classMemberDeclaration.parent;
30+
if (!classDeclaration || !isClassLike(classDeclaration)) {
31+
return undefined;
32+
}
3133

34+
const isStatic = hasModifier(getThisContainer(token, /*includeArrowFunctions*/ false), ModifierFlags.Static);
35+
36+
return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile();
3237

3338
function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined {
3439
let typeString = "any";
@@ -43,47 +48,71 @@ namespace ts.codefix {
4348

4449
const startPos = classDeclaration.members.pos;
4550

46-
return [{
51+
const actions = [{
4752
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
4853
changes: [{
4954
fileName: sourceFile.fileName,
5055
textChanges: [{
5156
span: { start: startPos, length: 0 },
52-
newText: `${token.getFullText(sourceFile)}: ${typeString};`
53-
}]
54-
}]
55-
},
56-
{
57-
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
58-
changes: [{
59-
fileName: sourceFile.fileName,
60-
textChanges: [{
61-
span: { start: startPos, length: 0 },
62-
newText: `[name: string]: ${typeString};`
57+
newText: `${isStatic ? "static " : ""}${token.getFullText(sourceFile)}: ${typeString};`
6358
}]
6459
}]
6560
}];
66-
}
6761

68-
function getActionsForAddMissingMemberInJavaScriptFile(): CodeAction[] | undefined {
69-
const classConstructor = getFirstConstructorWithBody(classDeclaration);
70-
if (!classConstructor) {
71-
return undefined;
62+
if (!isStatic) {
63+
actions.push({
64+
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
65+
changes: [{
66+
fileName: sourceFile.fileName,
67+
textChanges: [{
68+
span: { start: startPos, length: 0 },
69+
newText: `[x: string]: ${typeString};`
70+
}]
71+
}]
72+
});
7273
}
7374

75+
return actions;
76+
}
77+
78+
function getActionsForAddMissingMemberInJavaScriptFile(): CodeAction[] | undefined {
7479
const memberName = token.getText();
75-
const startPos = classConstructor.body.getEnd() - 1;
7680

77-
return [{
78-
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]),
79-
changes: [{
80-
fileName: sourceFile.fileName,
81-
textChanges: [{
82-
span: { start: startPos, length: 0 },
83-
newText: `this.${memberName} = undefined;`
81+
if (isStatic) {
82+
if (classDeclaration.kind === SyntaxKind.ClassExpression) {
83+
return undefined;
84+
}
85+
86+
const className = classDeclaration.name.getText();
87+
88+
return [{
89+
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_static_property_0), [memberName]),
90+
changes: [{
91+
fileName: sourceFile.fileName,
92+
textChanges: [{
93+
span: { start: classDeclaration.getEnd(), length: 0 },
94+
newText: `${context.newLineCharacter}${className}.${memberName} = undefined;${context.newLineCharacter}`
95+
}]
8496
}]
85-
}]
86-
}];
97+
}];
98+
}
99+
else {
100+
const classConstructor = getFirstConstructorWithBody(classDeclaration);
101+
if (!classConstructor) {
102+
return undefined;
103+
}
104+
105+
return [{
106+
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]),
107+
changes: [{
108+
fileName: sourceFile.fileName,
109+
textChanges: [{
110+
span: { start: classConstructor.body.getEnd() - 1, length: 0 },
111+
newText: `this.${memberName} = undefined;${context.newLineCharacter}`
112+
}]
113+
}]
114+
}];
115+
}
87116
}
88117
}
89118
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////[|class C {
4+
//// method() {
5+
//// this.foo = 10;
6+
//// }
7+
////}|]
8+
9+
verify.rangeAfterCodeFix(`class C {
10+
foo: number;
11+
method() {
12+
this.foo = 10;
13+
}
14+
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////[|class C {
4+
//// method() {
5+
//// this.foo = 10;
6+
//// }
7+
////}|]
8+
9+
verify.rangeAfterCodeFix(`class C {
10+
[x:string]: number;
11+
method() {
12+
this.foo = 10;
13+
}
14+
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 1);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////[|class C {
4+
//// static method() {
5+
//// this.foo = 10;
6+
//// }
7+
////}|]
8+
9+
verify.rangeAfterCodeFix(`class C {
10+
static foo: number;
11+
static method() {
12+
this.foo = 10;
13+
}
14+
}`);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @checkJs: true
4+
// @allowJs: true
5+
6+
// @Filename: a.js
7+
////[|class C {
8+
//// constructor() {
9+
//// }
10+
//// method() {
11+
//// this.foo === 10;
12+
//// }
13+
////}|]
14+
15+
verify.rangeAfterCodeFix(`class C {
16+
constructor() {
17+
this.foo = undefined;
18+
}
19+
method() {
20+
this.foo === 10;
21+
}
22+
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @checkJs: true
4+
// @allowJs: true
5+
6+
// @Filename: a.js
7+
////[|class C {
8+
//// static method() {
9+
//// ()=>{ this.foo === 10 };
10+
//// }
11+
////}
12+
////|]
13+
14+
verify.rangeAfterCodeFix(`class C {
15+
static method() {
16+
()=>{ this.foo === 10 };
17+
}
18+
}
19+
C.foo = undefined;`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @checkJs: true
4+
// @allowJs: true
5+
6+
// @Filename: a.js
7+
////[|class C {
8+
//// constructor() {
9+
//// }
10+
//// prop = ()=>{ this.foo === 10 };
11+
////}|]
12+
13+
verify.rangeAfterCodeFix(`class C {
14+
constructor() {
15+
this.foo = undefined;
16+
}
17+
prop = ()=>{ this.foo === 10 };
18+
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @checkJs: true
4+
// @allowJs: true
5+
6+
// @Filename: a.js
7+
////[|class C {
8+
//// static p = ()=>{ this.foo === 10 };
9+
////}
10+
////|]
11+
12+
verify.rangeAfterCodeFix(`class C {
13+
static p = ()=>{ this.foo === 10 };
14+
}
15+
C.foo = undefined;`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 2);

tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
verify.rangeAfterCodeFix(`
1010
class A {
11-
[name: string]: number;
11+
[x: string]: number;
1212
1313
constructor() {
1414
this.x = 10;

0 commit comments

Comments
 (0)