Skip to content

Commit b61d485

Browse files
author
Andy
authored
Simplify convertToMappedObjectType (microsoft#24360)
1 parent 10ac8b4 commit b61d485

File tree

1 file changed

+26
-64
lines changed

1 file changed

+26
-64
lines changed

src/services/codefixes/convertToMappedObjectType.ts

Lines changed: 26 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -6,89 +6,51 @@ namespace ts.codefix {
66

77
type FixableDeclaration = InterfaceDeclaration | TypeAliasDeclaration;
88

9-
interface Info {
10-
indexSignature: IndexSignatureDeclaration;
11-
container: FixableDeclaration;
12-
otherMembers: ReadonlyArray<TypeElement>;
13-
parameterName: Identifier;
14-
parameterType: TypeNode;
15-
}
16-
179
registerCodeFix({
1810
errorCodes,
1911
getCodeActions: context => {
2012
const { sourceFile, span } = context;
21-
const info = getFixableSignatureAtPosition(sourceFile, span.start);
22-
if (!info) return;
23-
const { indexSignature, container, otherMembers, parameterName, parameterType } = info;
24-
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)])];
13+
const info = getInfo(sourceFile, span.start);
14+
if (!info) return undefined;
15+
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info));
16+
const name = idText(info.container.name);
17+
return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [Diagnostics.Convert_0_to_mapped_object_type, name])];
2718
},
2819
fixIds: [fixId],
2920
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
30-
const info = getFixableSignatureAtPosition(diag.file, diag.start);
31-
if (!info) return;
32-
const { indexSignature, container, otherMembers, parameterName, parameterType } = info;
33-
34-
doChange(changes, context.sourceFile, indexSignature, container, otherMembers, parameterName, parameterType);
21+
const info = getInfo(diag.file, diag.start);
22+
if (info) doChange(changes, diag.file, info);
3523
})
3624
});
3725

38-
function isFixableParameterName(node: Node): boolean {
39-
return node && node.parent && node.parent.parent && node.parent.parent.parent && !isClassDeclaration(node.parent.parent.parent);
40-
}
41-
42-
function getFixableSignatureAtPosition(sourceFile: SourceFile, pos: number): Info | undefined {
26+
interface Info { readonly indexSignature: IndexSignatureDeclaration; readonly container: FixableDeclaration; }
27+
function getInfo(sourceFile: SourceFile, pos: number): Info | undefined {
4328
const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
44-
if (!isFixableParameterName(token)) return undefined;
45-
46-
const indexSignature = <IndexSignatureDeclaration>token.parent.parent;
47-
const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : <TypeAliasDeclaration>indexSignature.parent.parent;
48-
const members = isInterfaceDeclaration(container) ? container.members : (<TypeLiteralNode>container.type).members;
49-
const otherMembers = filter(members, member => !isIndexSignatureDeclaration(member));
50-
const parameter = first(indexSignature.parameters);
51-
52-
return {
53-
indexSignature,
54-
container,
55-
otherMembers,
56-
parameterName: <Identifier>parameter.name,
57-
parameterType: parameter.type!
58-
};
29+
const indexSignature = cast(token.parent.parent, isIndexSignatureDeclaration);
30+
if (isClassDeclaration(indexSignature.parent)) return undefined;
31+
const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : cast(indexSignature.parent.parent, isTypeAliasDeclaration);
32+
return { indexSignature, container };
5933
}
6034

61-
function getInterfaceHeritageClauses(declaration: FixableDeclaration): NodeArray<ExpressionWithTypeArguments> | undefined {
62-
if (!isInterfaceDeclaration(declaration)) return undefined;
63-
64-
const heritageClause = getHeritageClause(declaration.heritageClauses, SyntaxKind.ExtendsKeyword);
65-
return heritageClause && heritageClause.types;
35+
function createTypeAliasFromInterface(declaration: FixableDeclaration, type: TypeNode): TypeAliasDeclaration {
36+
return createTypeAliasDeclaration(declaration.decorators, declaration.modifiers, declaration.name, declaration.typeParameters, type);
6637
}
6738

68-
function createTypeAliasFromInterface(indexSignature: IndexSignatureDeclaration, declaration: FixableDeclaration, otherMembers: ReadonlyArray<TypeElement>, parameterName: Identifier, parameterType: TypeNode) {
69-
const heritageClauses = getInterfaceHeritageClauses(declaration);
70-
const mappedTypeParameter = createTypeParameterDeclaration(parameterName, parameterType);
39+
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { indexSignature, container }: Info): void {
40+
const members = isInterfaceDeclaration(container) ? container.members : (<TypeLiteralNode>container.type).members;
41+
const otherMembers = members.filter(member => !isIndexSignatureDeclaration(member));
42+
const parameter = first(indexSignature.parameters);
43+
const mappedTypeParameter = createTypeParameterDeclaration(cast(parameter.name, isIdentifier), parameter.type);
7144
const mappedIntersectionType = createMappedTypeNode(
7245
hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
7346
mappedTypeParameter,
7447
indexSignature.questionToken,
7548
indexSignature.type);
76-
77-
return createTypeAliasDeclaration(
78-
declaration.decorators,
79-
declaration.modifiers,
80-
declaration.name,
81-
declaration.typeParameters,
82-
createIntersectionTypeNode(
83-
concatenate(
84-
heritageClauses,
85-
append<TypeNode>([mappedIntersectionType], otherMembers.length ? createTypeLiteralNode(otherMembers) : undefined)
86-
)
87-
)
88-
);
89-
}
90-
91-
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, indexSignature: IndexSignatureDeclaration, declaration: FixableDeclaration, otherMembers: ReadonlyArray<TypeElement>, parameterName: Identifier, parameterType: TypeNode) {
92-
changes.replaceNode(sourceFile, declaration, createTypeAliasFromInterface(indexSignature, declaration, otherMembers, parameterName, parameterType));
49+
const intersectionType = createIntersectionTypeNode([
50+
...getAllSuperTypeNodes(container),
51+
mappedIntersectionType,
52+
...(otherMembers.length ? [createTypeLiteralNode(otherMembers)] : emptyArray),
53+
]);
54+
changes.replaceNode(sourceFile, container, createTypeAliasFromInterface(container, intersectionType));
9355
}
9456
}

0 commit comments

Comments
 (0)