@@ -4,74 +4,84 @@ namespace ts.codefix {
4
4
const fixId = fixIdAddMissingTypeof ;
5
5
const errorCodes = [ Diagnostics . An_index_signature_parameter_type_cannot_be_a_union_type_Consider_using_a_mapped_object_type_instead . code ] ;
6
6
7
+ type FixableDeclaration = InterfaceDeclaration | TypeAliasDeclaration ;
8
+
7
9
interface Info {
8
10
indexSignature : IndexSignatureDeclaration ;
9
- container : InterfaceDeclaration ;
11
+ container : FixableDeclaration ;
12
+ otherMembers : ReadonlyArray < TypeElement > ;
13
+ parameterName : Identifier ;
14
+ parameterType : TypeNode ;
10
15
}
11
16
12
17
registerCodeFix ( {
13
18
errorCodes,
14
19
getCodeActions : context => {
15
20
const { sourceFile, span } = context ;
16
- const info = getConvertibleSignatureAtPosition ( sourceFile , span . start ) ;
21
+ const info = getFixableSignatureAtPosition ( sourceFile , span . start ) ;
17
22
if ( ! info ) return ;
18
- const { indexSignature, container } = info ;
23
+ const { indexSignature, container, otherMembers , parameterName , parameterType } = info ;
19
24
20
- const changes = textChanges . ChangeTracker . with ( context , t => doChange ( t , sourceFile , indexSignature , container ) ) ;
21
- return [ createCodeFixAction ( fixId , changes , [ Diagnostics . Convert_0_to_mapped_object_type , "" ] , fixId , [ Diagnostics . Convert_0_to_mapped_object_type , "" ] ) ] ;
25
+ const changes = textChanges . ChangeTracker . with ( context , t => doChange ( t , sourceFile , indexSignature , container , otherMembers , parameterName , parameterType ) ) ;
26
+ return [ createCodeFixAction ( fixId , changes , [ Diagnostics . Convert_0_to_mapped_object_type , idText ( container . name ) ] , fixId , [ Diagnostics . Convert_0_to_mapped_object_type , idText ( container . name ) ] ) ] ;
22
27
} ,
23
28
fixIds : [ fixId ] ,
24
29
getAllCodeActions : context => codeFixAll ( context , errorCodes , ( changes , diag ) => {
25
- const info = getConvertibleSignatureAtPosition ( diag . file , diag . start ) ;
30
+ const info = getFixableSignatureAtPosition ( diag . file , diag . start ) ;
26
31
if ( ! info ) return ;
27
- const { indexSignature, container } = info ;
32
+ const { indexSignature, container, otherMembers , parameterName , parameterType } = info ;
28
33
29
- doChange ( changes , context . sourceFile , indexSignature , container ) ;
34
+ doChange ( changes , context . sourceFile , indexSignature , container , otherMembers , parameterName , parameterType ) ;
30
35
} )
31
36
} ) ;
32
37
38
+ function isFixableDeclaration ( node : Node ) : node is FixableDeclaration {
39
+ return isInterfaceDeclaration ( node ) || ( node . parent && isTypeLiteralNode ( node ) && isTypeAliasDeclaration ( node . parent ) ) ;
40
+ }
41
+
33
42
function isIndexSignatureParameterName ( node : Node ) : node is Identifier {
34
43
return node && node . parent && node . parent . parent && node . parent . parent . parent &&
35
- isIdentifier ( node ) && isParameter ( node . parent ) && isIndexSignatureDeclaration ( node . parent . parent ) && isInterfaceDeclaration ( node . parent . parent . parent ) ;
44
+ isIdentifier ( node ) && isParameter ( node . parent ) && isIndexSignatureDeclaration ( node . parent . parent ) && isFixableDeclaration ( node . parent . parent . parent ) ;
36
45
}
37
46
38
- function getConvertibleSignatureAtPosition ( sourceFile : SourceFile , pos : number ) : Info | undefined {
47
+ function getFixableSignatureAtPosition ( sourceFile : SourceFile , pos : number ) : Info | undefined {
39
48
const token = getTokenAtPosition ( sourceFile , pos , /*includeJsDocComment*/ false ) ;
40
49
if ( ! isIndexSignatureParameterName ( token ) ) return undefined ;
41
50
42
51
const indexSignature = < IndexSignatureDeclaration > token . parent . parent ;
43
- const container = < InterfaceDeclaration > indexSignature . parent ;
52
+ const container : FixableDeclaration = isInterfaceDeclaration ( indexSignature . parent ) ? indexSignature . parent : < TypeAliasDeclaration > indexSignature . parent . parent ;
53
+ const members = isInterfaceDeclaration ( container ) ? container . members : ( < TypeLiteralNode > container . type ) . members ;
54
+ const otherMembers = filter ( members , member => ! isIndexSignatureDeclaration ( member ) ) ;
55
+ const parameter = first ( indexSignature . parameters ) ;
44
56
45
57
return {
46
58
indexSignature,
47
- container
59
+ container,
60
+ otherMembers,
61
+ parameterName : < Identifier > parameter . name ,
62
+ parameterType : parameter . type
48
63
} ;
49
64
}
50
65
51
- function createTypeAliasFromInterface ( indexSignature : IndexSignatureDeclaration , declaration : InterfaceDeclaration ) {
52
- const otherMembersType = createTypeLiteralNode ( filter ( declaration . members , member => ! isIndexSignatureDeclaration ( member ) ) ) ;
53
- const parameter = first ( indexSignature . parameters ) ;
54
- const mappedObjectType = createMappedTypeNode (
55
- hasReadonlyModifier ( indexSignature ) ? createModifier ( SyntaxKind . ReadonlyKeyword ) : undefined ,
56
- createTypeParameterDeclaration (
57
- < Identifier > parameter . name ,
58
- parameter . type
59
- ) ,
60
- indexSignature . questionToken ,
61
- indexSignature . type
62
- ) ;
66
+ function createTypeAliasFromInterface ( indexSignature : IndexSignatureDeclaration , declaration : FixableDeclaration , otherMembers : ReadonlyArray < TypeElement > , parameterName : Identifier , parameterType : TypeNode ) {
67
+ const mappedIntersectionType : TypeNode [ ] = [
68
+ createMappedTypeNode (
69
+ hasReadonlyModifier ( indexSignature ) ? createModifier ( SyntaxKind . ReadonlyKeyword ) : undefined ,
70
+ createTypeParameterDeclaration ( parameterName , parameterType ) ,
71
+ indexSignature . questionToken ,
72
+ indexSignature . type )
73
+ ] ;
63
74
64
75
return createTypeAliasDeclaration (
65
76
declaration . decorators ,
66
77
declaration . modifiers ,
67
78
declaration . name ,
68
79
declaration . typeParameters ,
69
- createIntersectionTypeNode ( [ mappedObjectType , otherMembersType ] )
80
+ createIntersectionTypeNode ( append ( mappedIntersectionType , otherMembers . length ? createTypeLiteralNode ( otherMembers ) : undefined ) )
70
81
) ;
71
82
}
72
83
73
- function doChange ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , indexSignature : IndexSignatureDeclaration , declaration : InterfaceDeclaration ) {
74
- const newTypeDeclaration = createTypeAliasFromInterface ( indexSignature , declaration ) ;
75
- changes . replaceNode ( sourceFile , declaration , newTypeDeclaration ) ;
84
+ function doChange ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , indexSignature : IndexSignatureDeclaration , declaration : FixableDeclaration , otherMembers : ReadonlyArray < TypeElement > , parameterName : Identifier , parameterType : TypeNode ) {
85
+ changes . replaceNode ( sourceFile , declaration , createTypeAliasFromInterface ( indexSignature , declaration , otherMembers , parameterName , parameterType ) ) ;
76
86
}
77
87
}
0 commit comments