Refactoring & Quick fixes
Availability
Refactorings
Refactorings are supported as of Visual Studio 2017 version 15.4.0.
TS Version | Effects |
---|---|
2.4.0 | Convert to ES6 class |
2.5.0 | Extract function |
2.6.0 | Extract constant |
2.6.1 | Annotate with type from JSDoc |
2.6.1 | Install @types for JS module |
TBD | Convert to default import |
Code Fixes
Code fixes are supported as of Visual Studio 2017 version 15.0.0.
TS Version | Error Codes | Effects |
---|---|---|
2.1.4 | 2304, 2503, 2552, 2686 | Add an appropriate import (?) |
2.2.1 | 2339, 2551 | Add missing member |
2.2.1 | 2377 | Synthesize missing super() call |
2.2.1 | 2420 | Implement interface members |
2.2.1 | 2515, 2653 | Implement abstract members from base class |
2.2.1 | 2663 | Prepend this. to member access |
2.2.1 | 2689 | Change extends to implements |
2.2.1 | 17009 | Move super() call ahead of this access |
2.3.0 | All | Suppress JS diagnostic |
2.4.0 | 2551, 2552 | Correct misspelled name |
2.4.1 | 6133, 6138 | Handle unused symbol |
2.5.0 | 2713 | Rewrite as indexed access type |
2.5.0 | 8020 | Convert JSDoc type to TS type |
2.6.1 | 1329 | Call decorator factory expression |
2.6.1 | 7005, 7006, 7008, 7010, 7019, 7032, 7033, 7034 | Annotate with inferred type |
2.6.1 | 7016 | Install @types for JS module |
Examples
Refactorings
Convert to ES6 Class
Before
function cls() {
this.x = 10;
}
cls.prototype.method = function () {
return 3;
}
After
class cls
{
constructor()
{
this.x = 10;
}
method()
{
return 3;
}
}
Notes
- Only applies in JavaScript files.
- The caret must be on an occurrence of the class name.
Extract Function
Before
function F(x: number)
{
/*start*/return x + 1;/*end*/
}
After - Nested Function
function F(x: number)
{
return newFunction();
function newFunction()
{
return x + 1;
}
}
After - Top-Level Function
function F(x: number)
{
return newFunction(x);
}
function newFunction(x: number)
{
return x + 1;
}
Notes
- Extraction is best-effort - the resulting code may not compile or may behave subtly differently.
- After the refactoring, the caret should be at the beginning of the call to the extracted function.
Extract Constant
Before
const PI = 3.141;
class Circle {
readonly radius = 3;
Area() {
return /*start*/PI * (this.radius ** 2)/*end*/;
}
}
After - Local
const PI = 3.141;
class Circle {
readonly radius = 3;
Area() {
const newLocal = PI * (this.radius ** 2);
return newLocal;
}
}
After - Property
const PI = 3.141;
class Circle {
readonly radius = 3;
private readonly newProperty = PI * (this.radius ** 2);
Area() {
return this.newProperty;
}
}
Notes
- The extracted range must be an expression (exception
- Extraction is best-effort - the resulting code may not compile or may behave subtly differently. In particular, evaluation order may change.
- After the refactoring, the caret should be at the beginning of the call to the extracted constant/property.
Annotate with Type from JSDoc
Before
/** @type {number} */
var x;
After
/** @type {number} */
var x: number;
Notes
- The caret must be on the name of the declaration to be annotated.
Install @types for JS Module
Before
import "left-pad";
After
import "left-pad";
Notes
- The caret must be on the name of module being imported.
- No change is made to the source. Instead, the corresponding @types module for the module being imported is installed in the project.
- The refactoring will not be offered if no corresponding @types module is available.
- If there is an error, the corresponding code fix will be offered instead.
Convert to Default Import
Before
// @Filename: /a.d.ts
declare const x: number;
export = x;
// @Filename: /b.ts
import * as a from "./a";
// @Filename: /c.ts
import a = require("./a");
After
// @Filename: /a.d.ts
declare const x: number;
export = x;
// @Filename: /b.ts
import a from "./a";
// @Filename: /c.ts
import a from "./a";
Notes
- Currently this will only activate if
--allowSyntheticDefaultImports
is enabled. - The caret must be on the name of the module being imported.
Code Fixes
Add Missing Member
Before - TS2339
class C {
}
const c = new C();
c.P = 1; // TS2339
After - Property
class C {
P: number;
}
const c = new C();
c.P = 1;
After - Index Signature
class C {
[x: string]: number;
}
const c = new C();
c.P = 1;
Before - TS2551
class C {
Prop1: number;
}
const c = new C();
c.Prop2 = 1; // TS2551
After - Property
class C {
Prop2: number;
Prop1: number;
}
const c = new C();
c.Prop2 = 1;
After - Index Signature
class C {
[x: string]: number;
Prop1: number;
}
const c = new C();
c.Prop2 = 1;
Notes
- The receiver must have a class type.
Synthesize Missing super()
Call
Before - TS2377
class Base {
}
class Derived extends Base {
constructor() { //TS2377
}
}
After
class Base {
}
class Derived extends Base {
constructor() {
super();
}
}
Notes
- Always calls
super()
without arguments.
Implement Interface Members
Before - TS2420
interface I {
X: number
}
class C implements I { //TS2420
}
After
interface I {
X: number
}
class C implements I {
X: number;
}
Implement Abstract members from Base Class
Before - TS2515
abstract class A {
abstract M();
}
class C extends A { //TS2515
}
After
abstract class A {
abstract M();
}
class C extends A {
M() {
throw new Error("Method not implemented.");
}
}
Before - TS2563
abstract class A {
abstract M();
}
const c = class C extends A { //TS2563
}
After
abstract class A {
abstract M();
}
const c = class C extends A {
M() {
throw new Error("Method not implemented.");
}
}
Prepend this.
to Member Access
Before - TS2663
class C {
private x: number;
Increment() {
x++; //TS2663
}
}
After
class C {
private x: number;
Increment() {
this.x++;
}
}
Change extends
to implements
Before - TS2689
interface I {
}
class C extends I { //TS2689
}
After
interface I {
}
class C implements I {
}
Move super()
Call Ahead of this
Access
Before - TS17009
class Base {
}
class Derived extends Base {
private x: number;
constructor() {
this.x = 1; //TS17009
super();
}
}
After
class Base {
}
class Derived extends Base {
private x: number;
constructor() {
super();
this.x = 1;
}
}
Suppress JS Diagnostic
Before
// @ts-check
x++;
After - Suppress Single
// @ts-check
// @ts-ignore
x++;
After - Suppress File
// @ts-nocheck
x++;
Correct Misspelled Name
Before - TS2551
class C {
Prop1: number;
}
const c = new C();
c.Prop2 = 1; // TS2551
After
class C {
Prop1: number;
}
const c = new C();
c.Prop1 = 1;
Before - TS2552
let variable1 = 1;
variable2++; //TS2552
After
let variable1 = 1;
variable1++;
Notes
- There are restrictions on what counts as a misspelling - the lengths must match and be greater than 3, etc.
Handle Unused Symbol
Before - TS6133
// { "compilerOptions": { "noUnusedParameters": true } }
function F(x: number) { //TS6133
}
After - Remove Declaration
// { "compilerOptions": { "noUnusedParameters": true } }
function F() {
}
After - Prepend Underscore
// { "compilerOptions": { "noUnusedParameters": true } }
function F(_x: number) {
}
Before - TS6138
// { "compilerOptions": { "noUnusedLocals": true } }
class C {
constructor(private x: number) { //TS6138
}
}
After - Remove Declaration
// { "compilerOptions": { "noUnusedLocals": true } }
class C {
constructor() {
}
}
After - Prepend Underscore
// { "compilerOptions": { "noUnusedLocals": true } }
class C {
constructor(private _x: number) {
}
}
Notes
- Prepending an underscore to a constructor parameter declaring a property doesn't fix the error.
Rewrite as Indexed Access Type
Before - TS2713
interface I {
x: number;
}
let z: I.x; //TS2713
After
interface I {
x: number;
}
let z: I["x"];
Notes
- Presently, doesn't work for classes.
Convert JSDoc Type to TS Type
Before - TS8020
// { "compilerOptions": {"strictNullChecks": true} }
let x: ?number; //TS8020
After - null
// { "compilerOptions": {"strictNullChecks": true} }
let x: number | null;
After - null, undefined
// { "compilerOptions": {"strictNullChecks": true} }
let x: number | null | undefined;
Notes
- Not offered in JS files.
Call Decorator Factory Expression
Before - TS1329
// { "compilerOptions": {"experimentalDecorators": true, "target": "es5"} }
function DecoratorFactory() {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
}
}
class C {
@DecoratorFactory //TS1329
M() { }
}
After
// { "compilerOptions": {"experimentalDecorators": true, "target": "es5"} }
function DecoratorFactory() {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
}
}
class C {
@DecoratorFactory()
M() { }
}