feat(25770): add Quick Fix to convert LiteralType to MappedType (#40226)

This commit is contained in:
Alex T
2020-09-08 14:18:53 -07:00
committed by GitHub
parent 6101fbca39
commit 6aec7f4676
6 changed files with 118 additions and 0 deletions
+8
View File
@@ -5335,6 +5335,10 @@
"category": "Message",
"code": 95002
},
"Convert '{0}' to '{1} in {0}'": {
"category": "Message",
"code": 95003
},
"Extract to {0} in {1}": {
"category": "Message",
"code": 95004
@@ -5403,6 +5407,10 @@
"category": "Message",
"code": 95020
},
"Convert all type literals to mapped type": {
"category": "Message",
"code": 95021
},
"Add all missing members": {
"category": "Message",
"code": 95022
@@ -0,0 +1,53 @@
/* @internal */
namespace ts.codefix {
const fixId = "convertLiteralTypeToMappedType";
const errorCodes = [Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0.code];
registerCodeFix({
errorCodes,
getCodeActions: context => {
const { sourceFile, span } = context;
const info = getInfo(sourceFile, span.start);
if (!info) {
return undefined;
}
const { name, constraint } = info;
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info));
return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_1_in_0, constraint, name], fixId, Diagnostics.Convert_all_type_literals_to_mapped_type)];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getInfo(diag.file, diag.start);
if (info) {
doChange(changes, diag.file, info);
}
})
});
interface Info {
container: TypeLiteralNode,
typeNode: TypeNode | undefined;
constraint: string;
name: string;
}
function getInfo(sourceFile: SourceFile, pos: number): Info | undefined {
const token = getTokenAtPosition(sourceFile, pos);
if (isIdentifier(token)) {
const propertySignature = cast(token.parent.parent, isPropertySignature);
const propertyName = token.getText(sourceFile);
return {
container: cast(propertySignature.parent, isTypeLiteralNode),
typeNode: propertySignature.type,
constraint: propertyName,
name: propertyName === "K" ? "P" : "K",
};
}
return undefined;
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { container, typeNode, constraint, name }: Info): void {
changes.replaceNode(sourceFile, container, factory.createMappedTypeNode(/*readonlyToken*/ undefined,
factory.createTypeParameterDeclaration(name, factory.createTypeReferenceNode(constraint)), /*questionToken*/ undefined, typeNode));
}
}
+1
View File
@@ -61,6 +61,7 @@
"codefixes/correctQualifiedNameToIndexedAccessType.ts",
"codefixes/convertToTypeOnlyExport.ts",
"codefixes/convertToTypeOnlyImport.ts",
"codefixes/convertLiteralTypeToMappedType.ts",
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
"codefixes/importFixes.ts",
"codefixes/fixImplicitThis.ts",
@@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
////type K = number | string;
////type T = {
//// [K]: number;
////}
verify.codeFix({
description: [ts.Diagnostics.Convert_0_to_1_in_0.message, "K", "P"],
index: 0,
newFileContent:
`type K = number | string;
type T = {
[P in K]: number;
}`
});
@@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
////type Keys = number | string;
////type T = {
//// [Keys]: number;
////}
verify.codeFix({
description: [ts.Diagnostics.Convert_0_to_1_in_0.message, "Keys", "K"],
index: 0,
newFileContent:
`type Keys = number | string;
type T = {
[K in Keys]: number;
}`
});
@@ -0,0 +1,24 @@
/// <reference path='fourslash.ts' />
////type K1 = number | string;
////type T1 = {
//// [K1]: number;
////}
////type K2 = number | string;
////type T2 = {
//// [K2]: number;
////}
verify.codeFixAll({
fixAllDescription: ts.Diagnostics.Convert_all_type_literals_to_mapped_type.message,
fixId: 'convertLiteralTypeToMappedType',
newFileContent:
`type K1 = number | string;
type T1 = {
[K in K1]: number;
}
type K2 = number | string;
type T2 = {
[K in K2]: number;
}`
});