1
- /* @internal */
1
+ /* @internal */
2
2
namespace ts . codefix {
3
3
registerCodeFix ( {
4
4
errorCodes : [ Diagnostics . Property_0_does_not_exist_on_type_1 . code ] ,
@@ -13,55 +13,106 @@ namespace ts.codefix {
13
13
// this.missing = 1;
14
14
// ^^^^^^^
15
15
const token = getTokenAtPosition ( sourceFile , start ) ;
16
-
17
16
if ( token . kind != SyntaxKind . Identifier ) {
18
17
return undefined ;
19
18
}
20
19
21
- const classDeclaration = getContainingClass ( token ) ;
22
- if ( ! classDeclaration ) {
20
+ if ( ! isPropertyAccessExpression ( token . parent ) || token . parent . expression . kind !== SyntaxKind . ThisKeyword ) {
23
21
return undefined ;
24
22
}
25
23
26
- if ( ! ( token . parent && token . parent . kind === SyntaxKind . PropertyAccessExpression ) ) {
24
+ const classMemberDeclaration = getThisContainer ( token , /*includeArrowFunctions*/ false ) ;
25
+ if ( ! isClassElement ( classMemberDeclaration ) ) {
27
26
return undefined ;
28
27
}
29
28
30
- if ( ( token . parent as PropertyAccessExpression ) . expression . kind !== SyntaxKind . ThisKeyword ) {
29
+ const classDeclaration = < ClassLikeDeclaration > classMemberDeclaration . parent ;
30
+ if ( ! classDeclaration || ! isClassLike ( classDeclaration ) ) {
31
31
return undefined ;
32
32
}
33
33
34
- let typeString = "any" ;
34
+ const isStatic = hasModifier ( getThisContainer ( token , /*includeArrowFunctions*/ false ) , ModifierFlags . Static ) ;
35
35
36
- if ( token . parent . parent . kind === SyntaxKind . BinaryExpression ) {
37
- const binaryExpression = token . parent . parent as BinaryExpression ;
36
+ return isInJavaScriptFile ( sourceFile ) ? getActionsForAddMissingMemberInJavaScriptFile ( ) : getActionsForAddMissingMemberInTypeScriptFile ( ) ;
38
37
39
- const checker = context . program . getTypeChecker ( ) ;
40
- const widenedType = checker . getWidenedType ( checker . getBaseTypeOfLiteralType ( checker . getTypeAtLocation ( binaryExpression . right ) ) ) ;
41
- typeString = checker . typeToString ( widenedType ) ;
42
- }
38
+ function getActionsForAddMissingMemberInTypeScriptFile ( ) : CodeAction [ ] | undefined {
39
+ let typeString = "any" ;
43
40
44
- const startPos = classDeclaration . members . pos ;
41
+ if ( token . parent . parent . kind === SyntaxKind . BinaryExpression ) {
42
+ const binaryExpression = token . parent . parent as BinaryExpression ;
45
43
46
- return [ {
47
- description : formatStringFromArgs ( getLocaleSpecificMessage ( Diagnostics . Add_declaration_for_missing_property_0 ) , [ token . getText ( ) ] ) ,
48
- changes : [ {
49
- fileName : sourceFile . fileName ,
50
- textChanges : [ {
51
- 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 } ;`
44
+ const checker = context . program . getTypeChecker ( ) ;
45
+ const widenedType = checker . getWidenedType ( checker . getBaseTypeOfLiteralType ( checker . getTypeAtLocation ( binaryExpression . right ) ) ) ;
46
+ typeString = checker . typeToString ( widenedType ) ;
47
+ }
48
+
49
+ const startPos = classDeclaration . members . pos ;
50
+
51
+ const actions = [ {
52
+ description : formatStringFromArgs ( getLocaleSpecificMessage ( Diagnostics . Add_declaration_for_missing_property_0 ) , [ token . getText ( ) ] ) ,
53
+ changes : [ {
54
+ fileName : sourceFile . fileName ,
55
+ textChanges : [ {
56
+ span : { start : startPos , length : 0 } ,
57
+ newText : `${ isStatic ? "static " : "" } ${ token . getFullText ( sourceFile ) } : ${ typeString } ;`
58
+ } ]
63
59
} ]
64
- } ]
65
- } ] ;
60
+ } ] ;
61
+
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
+ } ) ;
73
+ }
74
+
75
+ return actions ;
76
+ }
77
+
78
+ function getActionsForAddMissingMemberInJavaScriptFile ( ) : CodeAction [ ] | undefined {
79
+ const memberName = token . getText ( ) ;
80
+
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
+ } ]
96
+ } ]
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
+ }
116
+ }
66
117
}
67
118
}
0 commit comments